Composition
Combining clauses with AND, OR and NOT, and how precedence and grouping work.
Clauses combine into boolean expressions. A query is one expression, introduced
by MATCH.
MATCH DIRECTION("infrastructure security") CONE 0.3
AND NOT DISTANCE("routine monitoring") WITHIN 0.75
NAMESPACE "org:acme-corp"
{
"match": {
"and": [
{ "direction": { "toward": "infrastructure security", "cone": 0.3 } },
{ "not": { "distance": { "anchor": "routine monitoring", "within": 0.75 } } }
]
},
"namespace": { "include": ["org:acme-corp"] }
}
Precedence
From tightest to loosest: NOT, then AND, then OR. This is the usual
ordering, so a AND NOT b OR c groups as (a AND (NOT b)) OR c.
Parentheses override it, and are worth using whenever a query mixes AND and
OR — a reader should not have to remember the table:
MATCH (
DIRECTION("payment gateway") CONE 0.3
AND DISTANCE("timeout error") WITHIN 0.8
)
OR (
DIRECTION("database connection") CONE 0.3
AND CONTRAST(
ATTRACT ["connection pool", "resource exhaustion"],
REPEL ["query optimization", "index tuning"]
)
)
NAMESPACE "org:acme-corp"
The JSON form is a tree
The text form's precedence disappears in JSON, where nesting is explicit:
{ "and": [ <expression>, <expression> ] }
{ "or": [ <expression>, <expression> ] }
{ "not": <expression> }
A bare clause object is itself a valid expression, so a single-clause query needs no wrapper.
Arity
and and or take at least two children. A one-element and is an error
rather than a no-op, because it is nearly always a generation bug in a client
that built the array in a loop:
and: requires at least 2 children
or: requires at least 2 children
not takes exactly one:
not: requires exactly 1 child
A boolean node holds at most 16 children, and expressions nest at most 128 deep. See limits.
What composition does not define
SemQL says which messages fall inside the region. It does not define how a matching message is scored, how the scores of several clauses combine, or what a host does with a negated clause's score. Those are properties of the system running the query, not of the language, and different hosts may reasonably answer them differently.
A host may also decline clauses it cannot serve — a streaming subscription
cannot honour a TOP k that is only meaningful over a finite result set.
Consult your host's documentation for that.
Grammar
expression = term { "OR" term } ;
term = factor { "AND" factor } ;
factor = [ "NOT" ] atom ;
atom = clause | "(" expression ")" ;