Query DSL Reference
Full reference for Elasticsearch Query DSL query types. All examples assume `ES_URL` and `ES_API_KEY` are set.
Overview
Query DSL Reference
Full reference for Elasticsearch Query DSL query types. All examples assume ES_URL and ES_API_KEY are set.
Table of Contents
- Full-Text Queries
- Term-Level Queries
- Compound Queries
- Nested & Join Queries
- Geo Queries
- Special Queries
- Search Features
Full-Text Queries
match
Analyzes the query string and finds documents with matching terms:
{ "query": { "match": { "message": { "query": "error timeout", "operator": "and" } } } }
- Default operator is
or(any term matches) - Use
"operator": "and"to require all terms "fuzziness": "AUTO"enables typo tolerance
multi_match
Search across multiple fields:
{
"query": {
"multi_match": {
"query": "connection refused",
"fields": ["message", "error.message", "log.original"],
"type": "best_fields"
}
}
}
Types: best_fields (default), most_fields, cross_fields, phrase, phrase_prefix
match_phrase
Matches exact phrase in order:
{ "query": { "match_phrase": { "message": "connection refused" } } }
match_phrase_prefix
Like match_phrase but last term is a prefix (autocomplete):
{ "query": { "match_phrase_prefix": { "message": "connect" } } }
query_string
Lucene syntax — powerful but can throw parse errors on bad input:
{ "query": { "query_string": { "query": "message:error AND level:critical", "default_field": "message" } } }
simple_query_string
Safer version — never throws parse errors, ignores invalid syntax:
{ "query": { "simple_query_string": { "query": "error + timeout -debug", "fields": ["message"] } } }
Operators: + (AND), | (OR), - (NOT), "..." (phrase), * (prefix), (...) (precedence)
Term-Level Queries
These operate on exact values (no analysis). Use on keyword, numeric, date, boolean fields.
term
Exact match on a single value:
{ "query": { "term": { "level": { "value": "error" } } } }
⚠️ Don't use term on text fields — they're analyzed, so exact match won't work as expected.
terms
Match any of several values (like SQL IN):
{ "query": { "terms": { "level": ["error", "critical", "fatal"] } } }
range
Numeric/date ranges:
{ "query": { "range": { "@timestamp": { "gte": "now-1h", "lt": "now" } } } }
{ "query": { "range": { "response_time": { "gte": 500, "lte": 5000 } } } }
Operators: gt, gte, lt, lte. Date math: now, now-1d, now/d (round to day).
exists
Field exists and has a non-null value:
{ "query": { "exists": { "field": "error.message" } } }
wildcard
Wildcard pattern matching (* = any chars, ? = single char):
{ "query": { "wildcard": { "hostname": { "value": "web-prod-*" } } } }
⚠️ Leading wildcards (*error) are expensive. Avoid in production.
regexp
Regular expression match:
{ "query": { "regexp": { "path": { "value": "/api/v[0-9]+/users.*" } } } }
prefix
Matches documents where field starts with value:
{ "query": { "prefix": { "hostname": { "value": "web-" } } } }
fuzzy
Typo-tolerant matching:
{ "query": { "fuzzy": { "message": { "value": "eror", "fuzziness": "AUTO" } } } }
ids
Match by document IDs:
{ "query": { "ids": { "values": ["doc-1", "doc-2", "doc-3"] } } }
Compound Queries
bool
Combine multiple queries with boolean logic:
{
"query": {
"bool": {
"must": [ { "match": { "message": "error" } } ],
"filter": [ { "range": { "@timestamp": { "gte": "now-1h" } } } ],
"should": [ { "term": { "level": "critical" } } ],
"must_not": [ { "term": { "env": "dev" } } ],
"minimum_should_match": 1
}
}
}
must— required, contributes to scorefilter— required, does NOT contribute to score (faster, cacheable)should— optional boost (or required if no must/filter)must_not— excluded, does NOT contribute to score
Best practice: Put exact filters in filter, free-text in must.
boosting
Demote results matching a negative query without excluding them:
{
"query": {
"boosting": {
"positive": { "match": { "message": "error" } },
"negative": { "term": { "level": "debug" } },
"negative_boost": 0.2
}
}
}
constant_score
Wrap a filter to return a fixed score:
{ "query": { "constant_score": { "filter": { "term": { "level": "error" } }, "boost": 1.0 } } }
function_score
Custom scoring functions (decay, random, field_value_factor):
{
"query": {
"function_score": {
"query": { "match_all": {} },
"functions": [
{ "field_value_factor": { "field": "popularity", "modifier": "log1p" } }
]
}
}
}
Nested & Join Queries
nested
Query nested objects (requires nested field type in mapping):
{
"query": {
"nested": {
"path": "comments",
"query": {
"bool": {
"must": [
{ "match": { "comments.author": "david" } },
{ "range": { "comments.date": { "gte": "now-7d" } } }
]
}
}
}
}
}
has_child / has_parent
Join queries for parent-child relationships:
{ "query": { "has_child": { "type": "answer", "query": { "match": { "body": "elasticsearch" } } } } }
Geo Queries
geo_bounding_box
{
"query": {
"geo_bounding_box": {
"location": {
"top_left": { "lat": 43.1, "lon": -79.0 },
"bottom_right": { "lat": 42.8, "lon": -78.7 }
}
}
}
}
geo_distance
{ "query": { "geo_distance": { "distance": "10km", "location": { "lat": 42.886, "lon": -78.878 } } } }
Special Queries
match_all / match_none
{ "query": { "match_all": {} } }
{ "query": { "match_none": {} } }
script
Custom scoring/filtering via Painless scripts:
{
"query": {
"script": {
"script": {
"source": "doc['response_time'].value > params.threshold",
"params": { "threshold": 1000 }
}
}
}
}
Search Features
Sorting
{ "sort": [ { "@timestamp": "desc" }, { "_score": "desc" } ] }
Source filtering
{ "_source": ["message", "level", "@timestamp"] }
{ "_source": { "includes": ["error.*"], "excludes": ["error.stack"] } }
Highlighting
{ "highlight": { "fields": { "message": { "pre_tags": [">>"], "post_tags": ["<<"] } } } }
search_after (pagination beyond 10k)
{
"size": 100,
"sort": [ { "@timestamp": "desc" }, { "_id": "asc" } ],
"search_after": ["2026-01-31T12:00:00.000Z", "abc123"]
}
collapse (deduplicate by field)
{ "collapse": { "field": "hostname" }, "sort": [ { "@timestamp": "desc" } ] }
runtime fields (query-time computed fields)
{
"runtime_mappings": {
"duration_ms": {
"type": "double",
"script": "emit(doc['end_time'].value.toInstant().toEpochMilli() - doc['start_time'].value.toInstant().toEpochMilli())"
}
},
"query": { "range": { "duration_ms": { "gte": 1000 } } }
}