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
repelas 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 |