Full-text queries
|
This section documents the current Elasticsearch 9.x line (with 8.19 as the final 8.x release) as published at the Elasticsearch documentation, which is the reference these pages are written and verified against. No specific patch version is pinned. Some capabilities (Kibana-only UIs, the ML/NLP model-management workflow, cross-cluster replication, and parts of the paid / serverless-only surface) are linked, not documented in depth. This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production, as Elasticsearch iterates quickly. This section’s bibliography lists the reference material consulted while preparing these pages. |
Full-text queries run against text fields: the query string is analyzed into terms the same way
the field was at index time, then those terms are looked up in the inverted index and the matches
are scored with BM25. This page covers the match family, multi_match and combined_fields, and
the query_string / simple_query_string / intervals queries. For exact, non-analyzed matching
on keyword, numbers and dates, see
Term-level queries; for how these clauses
combine and score, see
Compound queries & relevance.
Overview:
Full text queries.
The search text is analyzed like the field
A full-text query is not a substring match. Elasticsearch passes the query string through an
analyzer — by default the field’s search_analyzer (falling back to its analyzer) — so "The
Quick Foxes" becomes [quick, fox] if the field uses the english analyzer, and those terms are
what get matched. This is why the same words find a document whether they were capitalized,
pluralized or reordered. See Text analysis for how
analyzers are built and tested, and
Text analysis for the
reference.
PUT /articles
{
"mappings": {
"properties": {
"title": { "type": "text", "analyzer": "english" },
"body": { "type": "text" },
"tag": { "type": "keyword" }
}
}
}
PUT /articles/_doc/1?refresh
{ "title": "The Quick Brown Foxes", "body": "A story about clever animals", "tag": "wildlife" }
# "foxes" is stemmed to "fox" by the english analyzer, so this matches.
GET /articles/_search
{ "query": { "match": { "title": "fox" } } }
If a full-text query returns nothing you expected, run the analyzer on both the field text and the
query string with the _analyze API and compare the terms — a mismatch there is the usual cause.
GET /articles/_analyze
{ "analyzer": "english", "text": "The Quick Brown Foxes" }
match
match is the standard full-text query for a single field. It analyzes the input, then builds a
boolean query over the resulting terms — by default any one term matching is enough (OR). See
Match query.
GET /articles/_search
{ "query": { "match": { "body": "clever animals" } } }
operator
Set operator to and to require every analyzed term to be present.
GET /articles/_search
{
"query": {
"match": {
"body": { "query": "clever animals", "operator": "and" }
}
}
}
minimum_should_match
With the default OR operator you can still demand that a fraction or count of the terms match.
minimum_should_match accepts an integer (3), a negative integer (-1 = all but one), a
percentage ("75%"), or a combined expression ("2<75%" = if there are more than 2 terms, require
75%). See
minimum_should_match parameter.
GET /articles/_search
{
"query": {
"match": {
"body": { "query": "a story about clever wild animals", "minimum_should_match": "75%" }
}
}
}
fuzziness
fuzziness allows edit-distance (Levenshtein) matches for typos. "AUTO" picks 0/1/2 edits based
on term length and is the recommended setting; prefix_length protects the first N characters from
edits and keeps the term expansion cheap.
GET /articles/_search
{
"query": {
"match": {
"title": { "query": "quik browne", "fuzziness": "AUTO", "prefix_length": 1 }
}
}
}
analyzer
analyzer overrides which analyzer processes the query string (the field’s own analyzer still
governs the indexed terms). Use it when the search-time tokenization should differ, e.g. a
standard analyzer for input that must not be stemmed.
GET /articles/_search
{
"query": {
"match": {
"title": { "query": "Foxes", "analyzer": "standard" }
}
}
}
match_phrase
match_phrase requires the analyzed terms to appear in order and adjacent (subject to slop, the
number of positional moves allowed). It needs the field to index positions, which text does by
default. See
Match phrase query.
GET /articles/_search
{
"query": {
"match_phrase": {
"body": { "query": "clever animals", "slop": 1 }
}
}
}
match_phrase_prefix
match_phrase_prefix treats the last term as a prefix — useful for "search as you type" against a
normal text field. It expands the last term to at most max_expansions (default 50) matching
terms, so results near the end of the alphabet can be missed; for real typeahead prefer the
search_as_you_type
field type. See
Match phrase prefix query.
GET /articles/_search
{
"query": {
"match_phrase_prefix": {
"title": { "query": "quick bro", "max_expansions": 20 }
}
}
}
multi_match
multi_match runs a match against several fields and combines the scores. The type parameter
decides how. See
Multi-match query.
GET /articles/_search
{
"query": {
"multi_match": {
"query": "clever foxes",
"fields": [ "title^3", "body" ],
"type": "best_fields"
}
}
}
Field names accept wildcards ("fields": [ "*_name" ]) and per-field boosts (title^3).
type |
Behaviour |
|---|---|
|
(default) Score each field separately, take the single best field’s score (plus
|
|
Sum the per-field scores. Best when the same text is indexed several ways (e.g. |
|
Treat the listed fields as one big field, term-centric: each query term must match in some
field (honours |
|
Like |
|
Like |
|
Like |
# Entity spread across two fields: "will smith" should match first_name=Will, last_name=Smith.
GET /people/_search
{
"query": {
"multi_match": {
"query": "will smith",
"type": "cross_fields",
"fields": [ "first_name", "last_name" ],
"operator": "and"
}
}
}
combined_fields
combined_fields is the modern term-centric multi-field query: it models the listed fields as one
combined field with a principled BM25 score across them, and supports operator and
minimum_should_match over the whole set. All fields must share the same search analyzer. Prefer it
over cross_fields for new work. See
Combined fields query.
GET /articles/_search
{
"query": {
"combined_fields": {
"query": "clever wild animals",
"fields": [ "title", "body" ],
"operator": "and"
}
}
}
query_string and simple_query_string
query_string parses a compact query language in the string itself: field prefixes (title:fox),
booleans (quick AND (brown OR red)), phrases ("quick brown"), wildcards (qu?ck, bro*), regex
(/joh?n/), proximity ("fox quick"~5), boosts (fox^2) and ranges (age:[18 TO 30]). A syntax
error in the string fails the whole request. Because of that, expose it only to trusted callers (an
internal console, a power-user search bar) — never pass raw end-user input to it. See
Query string query.
GET /articles/_search
{
"query": {
"query_string": {
"query": "(quick OR clever) AND animals",
"fields": [ "title^2", "body" ],
"default_operator": "AND"
}
}
}
simple_query_string is the version safe for a public search box: the same mini-language in a
simpler form (+ for AND, | for OR, - for NOT, "…" for phrase, * suffix for prefix, ~N
for fuzziness / slop), and it silently ignores malformed parts instead of erroring. You can disable
individual operators via flags. See
Simple query string query.
GET /articles/_search
{
"query": {
"simple_query_string": {
"query": "clever + animals -boring \"wild animals\"",
"fields": [ "title", "body" ],
"default_operator": "and",
"flags": "AND|OR|NOT|PHRASE|PREFIX"
}
}
}
Rule of thumb: use match / multi_match / combined_fields for application-built queries, reach
for simple_query_string only when users must type operators themselves, and reserve query_string
for internal tools. The Kibana Query Language (KQL) and the classic Lucene query syntax are covered
separately in
Query languages & scripting.
intervals
The intervals query matches ordered sequences of terms with fine control over gaps and ordering — more expressive than phrase/slop and evaluated per field. Rules like match, prefix, wildcard,
fuzzy are composed with all_of (ordered, all required), any_of (alternatives), and filters
such as max_gaps and ordered. Use it for "these words, in this order, within N words of each
other" requirements that match_phrase slop cannot express cleanly. See
Intervals query.
GET /articles/_search
{
"query": {
"intervals": {
"body": {
"all_of": {
"ordered": true,
"max_gaps": 3,
"intervals": [
{ "match": { "query": "clever" } },
{ "match": { "query": "animals" } }
]
}
}
}
}
}
Where to go next
-
Text analysis — the analyzers that decide what these queries actually match.
-
Term-level queries — exact matching on
keyword, numeric and date fields, with no analysis. -
Compound queries & relevance —
bool,dis_max,function_score, and how BM25 scoring is tuned. -
Search API & pagination — request structure,
_sourcefiltering, highlighting and paging through full-text results.