Skip to content

CONTRAST

Attract/repel vector arithmetic — "like these, unlike those" in one clause.

CONTRAST builds a composite vector by pulling toward one set of concepts and pushing away from another, then matches against a sphere around the result.

MATCH CONTRAST(
        ATTRACT ["enterprise", "high-value account"],
        REPEL   ["self-serve", "free tier"]
      ) WITHIN 0.75
NAMESPACE "org:acme-corp"
{
  "match": {
    "contrast": {
      "attract": ["enterprise", "high-value account"],
      "repel": ["self-serve", "free tier"],
      "within": 0.75
    }
  },
  "namespace": { "include": ["org:acme-corp"] }
}

Fields

Field Type Required Default Description
attract string[] yes Concepts to move toward
repel string[] no Concepts to move away from
within number no Similarity floor from the composite, 0.0–1.0

repel is optional

A CONTRAST with only attract is valid. The composite is then just the normalized mean of the attract anchors:

MATCH CONTRAST(ATTRACT ["home kitchen", "small appliance"]) WITHIN 0.7

Two published descriptions of SemQL mark repel as required — the specification's own EBNF, and Noetive's Semantik documentation. Both are wrong. The reference parser makes it optional in the text grammar and never checks for it during validation, so an attract-only query parses and runs.

How the composite is built

With both sets present:

normalize(mean(embed(attract)) - mean(embed(repel)))

With repel absent:

normalize(mean(embed(attract)))

Subtraction happens between the two means, not pairwise, so adding a fourth attract concept dilutes the other three rather than adding a new lobe to the region.

A repel set too close to the attract set leaves a composite that is mostly cancellation — short, unstable, and sensitive to noise. Repel concepts work best when they name a neighbouring topic you keep matching by accident, not the opposite of what you want.

within is a floor

As with DISTANCE, within is a minimum similarity to the composite vector. Higher is stricter, 0 means no floor, and values outside [0, 1] are rejected.

Grammar

The reference parser's grammar, which differs from the published EBNF as described above:

contrast_clause = "CONTRAST" "("
                    "ATTRACT" anchor_list
                    [ "," "REPEL" anchor_list ]
                  ")" [ "WITHIN" number ] ;

At most 8 anchors may appear in each of attract and repel — see limits.

Errors

Message Cause
contrast: at least one attract anchor is required Empty or absent attract
contrast: within must be in [0, 1] Out-of-range floor
contrast: within must be a finite number NaN or an infinity