Span queries #
Span queries are low-level positional queries that expose and control
the positions of terms — the building blocks for phrase-adjacent logic
that
phrase does not express directly.
Most use cases are better served by match_phrase (or its slop); the
span family exists for the remaining ones.
Inside a
nestedquery: not supported yet — span clauses are rejected with an HTTP 400 naming the offending clause. Usephrasewithslopfor positional logic.
How it works #
The engine rewrites each span query to its fastest equivalent before
execution. An in_order span_near whose clauses are all span_term
becomes the engine’s native
phrase query — reusing the
block-max-WAND phrase producer, the fastest position pipeline
available; on that path slop carries phrase-slop semantics (swapping
two adjacent terms costs 2 slop, so a reversed occurrence matches from
slop: 2). A root span_multi becomes its wrapped matcher and a
span_or becomes a bool.should. The residual shapes — multi-term
leaves inside span_near, unordered span_near — run a native
two-phase evaluator: phase one takes the clause AND (each clause’s
terms expanded from the dictionary) as the candidate set, phase two
decodes each candidate’s positions and counts alignments with a
per-pair gap budget (next.start − prev.end, ordered) or a minimal
covering window (unordered, the window-minus-widest-span rule).
Frequencies cap at 1024 alignments — match-ness is exact, only the
BM25 input is capped; the clause idf sum uses each clause’s rarest
term. Without a position index the family degrades to the clause AND,
exactly like phrase. span_term itself accepts three wire shapes:
{ "field": "value" }, { "field": { "value": "v" } } and
{ "field": …, "value": … }.
span_term
#
Matches documents containing an exact term at any position — the positional unit the other span queries compose.
POST /my-collection/_search
{
"query": {
"span_term": {
"field": "message",
"value": "search"
}
}
}
Parameters: field (required, string), value (required, string), boost
(optional, default 1.0).
span_near
#
Matches documents where the given span clauses occur within slop
positions of each other, optionally in order — the span form of a
proximity match — get within three positions of search, in order
(25 log lines in the dataset):
POST /my-collection/_search
{
"query": {
"span_near": {
"clauses": [
{ "span_term": { "field": "message", "value": "get" } },
{ "span_term": { "field": "message", "value": "search" } }
],
"slop": 3,
"in_order": true
}
}
}
clauses— (Required, array of span queries) The spans to relate.slop— (Optional, integer, default:0) Maximum positions between the clauses.in_order— (Optional, boolean, default:true) Whether the clauses must appear in the given order.
span_or
#
Matches documents matching any of the given span clauses — the union of spans.
{
"span_or": {
"clauses": [
{ "span_term": { "field": "message", "value": "get" } },
{ "span_term": { "field": "message", "value": "post" } }
]
}
}
clauses— (Required, array of span queries).
span_multi
#
Wraps a multi-term query (such as prefix, wildcard, fuzzy,
regexp, term) so it can be used as a span clause inside span_near /
span_or. The wrapped query sits under the match key:
{
"span_multi": {
"match": {
"prefix": { "field": "user", "value": "ki" }
}
}
}
match— (Required, query) The multi-term query to wrap.
Use cases #
- Proximity with a budget. The playground’s
get…searchwithinslop: 3keeps all 25GET /searchlines while admitting lines with a word between — the direct sibling ofphrase+slop. - Positional unions.
span_orofgetandpostmatches 125 of the 150 log lines (100 + 25, no overlap) — an OR that stays a span, so it can feed aspan_nearafterwards. - Pattern leaves in proximity.
span_multiwrappingprefix: clusterwithinslop: 2ofleft(in order) matches the 25cluster node left …lines — a wildcard family next to an anchor word, whichphrasecannot express at all. - Wire compatibility. Span pipelines arriving from existing clients run unchanged — all four clauses take the standard wire forms.
Related #
intervals— the other positional grammar: a declarative rule tree (all_of/any_of+ filter predicates) instead of clause composition. Prefer it for anything richer than near/or; prefer spans for the shapes above.phrase— what an all-span_termspan_nearbecomes internally; itsslopdocuments the shared slop metric.prefix,wildcard,fuzzy,regexp— the queriesspan_multiwraps.