Phrase query

Phrase query #

Returns documents that contain the exact sequence of terms, in order, with no other terms in between (modulo slop). The text is analyzed before matching, like the match query.

The query’s native name is phrase; the match_phrase spelling deserializes to the same query — an accepted alias, not a different feature.

Inside a nested query: supported — the phrase, including its slop, must be satisfied by ONE array element; terms keep query order.

How it works #

The text is analyzed — the field’s search analyzer (index analyzer as fallback, then standard), or analyzer when given — and every term must be present in the field’s dictionary: one unknown term and the phrase matches nothing, like an AND.

Order is verified against the position index. At slop 0 a start position is a hit only when every term sits exactly at its query offset from the lead — strict adjacency, no intervening terms. With slop > 0 the engine runs sloppy phrase scoring semantics: each term’s positions are adjusted by its query offset (an exact, in-order match collapses to a zero-width window), and a window holding one position per term matches when its spread max − min is within the slop budget. Reversed order matches too, but pays for the reversal out of the same budget — every position a term moves costs 1.

The match frequency — how many windows satisfy the budget — feeds a BM25-style phrase score:

score = idf_sum * (k1 + 1) * pf / (pf + k1 * (1 - b + b * dl / avgdl))

with k1 = 1.2, b = 0.75, idf_sum the sum of the per-term IDFs, and pf the window count. Term cursors are driven rarest-first under block-max WAND pruning, which makes the phrase pipeline one of the engine’s fastest.

Two fallbacks matter: a field indexed without positions degrades the phrase to a plain AND of its terms (no order constraint), and on a keyword field the whole phrase text is resolved as one exact term.

Examples #

The following search returns the lines whose message carries the phrase HTTP/1.1 200 — 75 of the 150 documents, the successful responses:

POST /my-collection/_search
{
  "query": {
    "phrase": {
      "field": "message",
      "query": "this is a test"
    }
  }
}

Allow words in between with slop:

POST /my-collection/_search
{
  "query": {
    "phrase": {
      "field": "message",
      "query": "this test",
      "slop": 3
    }
  }
}

Use cases #

  • Exact signatures. HTTP/1.1 200 in logs.message picks out the successful responses — 75 of 150 — where a match on the same text would also admit documents carrying the fragments in any order.
  • Error templates. Operational messages follow fixed templates (“node left the region”); the phrase pins the template while slop absorbs minor wording drift.
  • Word-order-sensitive data. Titles, names and commands, where “restore backup” and “backup restore” mean different things.
  • Controlled proximity. slop turns a phrase into a near-phrase: allow a word or two of insertion without falling back to a bag of terms.

Parameters for phrase #

  • field
    (Required, string) Field you wish to search.
  • query
    (Required, string) The phrase you wish to find in the provided field; analyzed before matching.
  • analyzer
    (Optional, string) Analyzer used to convert the text into terms. Defaults to the field’s search analyzer.
  • slop
    (Optional, float, default: 0) Maximum number of positions the terms may be shifted to match the phrase; 0 requires strict adjacency.
  • match — same analysis, but treats the tokens as an unordered bag.
  • multi_match — one phrase per field via type: "phrase".
  • span — position-level rules (order, gaps, proximity) when a slop budget is not expressive enough.
  • Analyzers — the token stream whose positions the phrase verifies.
  • API conventions.
Calendar October 6, 2026
Edit Edit this page