Elasticsearch Term Level Queries
Full text queries analyze the search text, split it into words, and match flexible variations. Term-level queries behave differently. They look for the exact value you type, with no analysis at all. They suit structured data such as IDs, status codes, dates, prices, and categories, where "close enough" is wrong.
The Most Common Beginner Mistake
A text field stores analyzed tokens, usually in lower case. A term query sends the raw value without analysis. A capital letter in the query fails to match the stored token.
Stored text field "title": "Gaming Laptop"
Tokens in the index: [gaming] [laptop]
term query for "Laptop" → looks for token "Laptop" → no match ✘
term query for "laptop" → looks for token "laptop" → match ✔
match query for "Laptop" → analyzes to "laptop" → match ✔
Use term-level queries on keyword, numeric, date, and boolean fields. Use match queries on text fields.
The term Query
GET /products/_search
{
"query": {
"term": { "status": "published" }
}
}
Add "case_insensitive": true inside the field object when the stored case varies and a keyword field is queried.
The terms Query
The terms query matches any value from a list, similar to IN in SQL.
{ "terms": { "color": ["red", "blue", "green"] } }
The range Query
Range queries work on numbers, dates, and strings. The operators are gt, gte, lt, and lte.
{ "range": { "price": { "gte": 20, "lte": 100 } } }
{ "range": { "created": { "gte": "now-7d/d", "lt": "now/d" } } }
The date math expression now-7d/d means seven days ago, rounded down to the start of that day. The query above selects everything created during the past seven complete days.
The exists Query
The exists query finds documents where a field has a value. Wrap it in a must_not clause to find documents where the field is missing.
{ "exists": { "field": "email" } }
{ "bool": { "must_not": { "exists": { "field": "phone" } } } }
The ids Query
{ "ids": { "values": ["1", "5", "42"] } }
Pattern Queries
Three queries match patterns inside keyword values. They scan many terms and cost more than exact lookups.
| Query | Pattern Style | Example |
|---|---|---|
| prefix | Value starts with text | { "prefix": { "code": "AB-" } } |
| wildcard | * means many characters, ? means one | { "wildcard": { "code": "AB-1??" } } |
| regexp | Regular expression | { "regexp": { "code": "AB-[0-9]{3}" } } |
Avoid wildcards that begin with * or ?. A leading wildcard forces Elasticsearch to examine every term in the field. Prefix queries or edge n-gram fields give much better speed.
Choosing a Query Type
| Field Type | Recommended Query |
|---|---|
| text | match, match_phrase |
| keyword | term, terms, prefix |
| integer, float | term, range |
| date | range |
| boolean | term |
Using Term-Level Queries in Filter Context
Exact matching has no relevance score worth computing. A product is either published or not. Place term-level queries inside a bool filter clause so Elasticsearch skips scoring and caches the result.
GET /products/_search
{
"query": {
"bool": {
"must": { "match": { "title": "laptop" } },
"filter": [
{ "term": { "status": "published" } },
{ "range": { "price": { "lte": 1000 } } }
]
}
}
}
match "laptop" → scored, ranks results by relevance
term + range → filters only, fast and cached
The combination delivers relevant results quickly: text relevance from the match clause, strict conditions from the filters.
Checking What Is Stored
A failed term query usually means the stored token differs from the typed value. Run the _analyze API on the field, or inspect the mapping with GET /products/_mapping. Seeing the real tokens ends most guessing sessions in seconds.
Date and Number Details
Dates compare as points in time, and the format of the query value must match the field format. A date field mapped with the default format accepts ISO strings such as 2026-11-05. Add a format parameter inside a range query when values arrive in another style, such as day-month-year.
{
"range": {
"order_date": {
"gte": "01/11/2026",
"lte": "05/11/2026",
"format": "dd/MM/yyyy"
}
}
}
Float fields carry rounding differences, so exact term matches on decimals can surprise. Use a narrow range query for prices and measurements instead of a single exact value.
