Choosing Between Term and Match Queries in Elasticsearch
Learn when to use 'term' vs 'match' queries in Elasticsearch to avoid the common problem of missing documents caused by field analysis mismatches.
08 May 2026, 12:57 UTC

The Search Mismatch Problem
A common failure point in Elasticsearch implementations is the "missing document" bug: a developer queries for a value they know exists in the index, but the API returns zero results. This usually happens because of a mismatch between the Query Type and the Field Mapping.
The core issue is Analysis. Analysis is the process of breaking a string into tokens (e.g., converting "Quick Brown Fox" to "quick", "brown", "fox"). If you search for a raw string against a field that has been tokenized, or search for a tokenized string against a field that hasn't, the values will not align, and the search will fail.
Decision Matrix: Term vs. Match
| Feature | Term Query | Match Query |
|---|---|---|
| Analysis | None (Exact match) | Analyzes search term first |
| Primary Field Type | keyword | text |
| Use Case | IDs, Statuses, Tags, Exact Filters | Descriptions, User-facing search |
| Case Sensitivity | Case-sensitive | Generally case-insensitive |
| Performance | Highly efficient (O(1) lookup) | Heavier (Analysis overhead) |
Trade-offs and Engineering Constraints
The Term Query Risk
Using a term query on a text field is a frequent mistake. Because text fields are analyzed during indexing (usually lowercased), searching for "Admin" via a term query will fail because the index actually contains "admin". The term query does not lowercase the input; it looks for the literal string "Admin".
The Match Query Overhead
While match is flexible, it is computationally more expensive. It must run the input through the same analyzer used at index time. For high-throughput filtering (e.g., filtering a dashboard by user_id), the match query introduces unnecessary latency and CPU cycles.
The Multi-field Solution
To support both exact filtering and full-text search on the same piece of data, use a multi-field mapping. This stores the data twice: once as text for searching and once as keyword for filtering.
Implementation Example
1. Define the Mapping
Run this command in the Dev Tools console or via curl to create an index with a multi-field for the city attribute. This requires cluster:admin/indices:create permissions.
PUT /location_index
{
"mappings": {
"properties": {
"city": {
"type": "text",
"fields": {
"raw": {
"type": "keyword"
}
}
}
}
}
}2. Index a Document
POST /location_index/_doc/1
{
"city": "New York"
}3. Validation Tests
Test A: Full-text search (Case-insensitive)
This uses the match query on the text field. It will succeed even with lowercase input because the analyzer handles both sides.
GET /location_index/_search
{
"query": {
"match": {
"city": "new york"
}
}
}Test B: Exact filter (Case-sensitive)
This uses the term query on the .raw sub-field. Note that searching for "new york" (lowercase) here will return zero results because the keyword type preserves the original casing.
GET /location_index/_search
{
"query": {
"term": {
"city.raw": "New York"
}
}
}Verification and Limitations
To verify your decision, use the _analyze API to see how your text is being broken down before choosing a query type:
POST /location_index/_analyze
{
"analyzer": "standard",
"text": "New York"
}Limitations:
- Index Size: Multi-fields increase the size of your index on disk because the data is stored in two different formats.
- Update Cost: Updating a document with multi-fields requires updating both the inverted index (for
text) and the doc values (forkeyword).
Rollback Procedure
Since Elasticsearch mappings cannot be changed after a field is created, you cannot "convert" a text field to a keyword field. To fix an incorrect mapping:
- Create a new index with the correct mapping.
- Use the
_reindexAPI to move data from the old index to the new one. - Delete the old index and create an alias to point the application to the new index.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.