Skip to content

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 ")" ;