# Elasticsearch Match Query vs Term Query: When to Use Each for Full-Text vs Exact Match

> Understand Elasticsearch match query vs term query. Use match for full-text search with analysis and relevance. Use term for exact matches on non-analyzed fields. Choose the right query for your search needs.

- Repository: [elastic/elasticsearch](https://github.com/elastic/elasticsearch)
- Tags: deep-dive
- Published: 2026-02-16

---

**Use a `match` query for full-text search on analyzed text fields where you need tokenization, stemming, and relevance scoring; use a `term` query for exact-value filtering on keyword, numeric, or other non-analyzed fields where the value must match verbatim without analysis.**

The `match` and `term` queries in Elasticsearch serve fundamentally different search purposes despite both locating documents containing specific values. According to the `elastic/elasticsearch` source code, the divergence begins at the analysis layer: `MatchQueryBuilder` processes input through the field's analyzer while `TermQueryBuilder` compares values directly against the indexed term dictionary without transformation.

## Core Architectural Differences

The primary distinction between these query types lies in whether the input text undergoes analysis before reaching Lucene's index.

### How Match Query Processes Text

When you execute a `match` query, the `MatchQueryBuilder` class in [`server/src/main/java/org/elasticsearch/index/query/MatchQueryBuilder.java`](https://github.com/elastic/elasticsearch/blob/main/server/src/main/java/org/elasticsearch/index/query/MatchQueryBuilder.java) orchestrates a multi-stage analysis pipeline. The builder's `doToQuery` method instantiates a `MatchQueryParser` (located in [`server/src/main/java/org/elasticsearch/index/search/MatchQueryParser.java`](https://github.com/elastic/elasticsearch/blob/main/server/src/main/java/org/elasticsearch/index/search/MatchQueryParser.java)) which applies the field's configured analyzer—tokenizing the input, converting to lowercase, applying stemming, and removing stop words.

The parser then constructs a Lucene Boolean query from the resulting tokens. By default, these tokens are joined with a Boolean `OR` clause, though you can specify `operator: and` to require all tokens. This architecture supports advanced features like `fuzziness`, `prefix_length`, and `minimum_should_match` parameters, which are forwarded directly to the `MatchQueryParser`.

### How Term Query Handles Values

In contrast, the `TermQueryBuilder` in [`server/src/main/java/org/elasticsearch/index/query/TermQueryBuilder.java`](https://github.com/elastic/elasticsearch/blob/main/server/src/main/java/org/elasticsearch/index/query/TermQueryBuilder.java) bypasses analysis entirely. Its `doToQuery` method retrieves the `MappedFieldType` for the target field and invokes `mapper.termQuery(value, context)`, creating a Lucene `TermQuery` that compares the supplied value verbatim against the indexed term dictionary.

Because no analyzer intervenes, the `term` query performs exact byte-level matching. This makes it ideal for keyword fields, numeric identifiers, and other non-analyzed data. The builder also implements `maybeRewriteBasedOnConstantFields`, which optimizes execution by rewriting constant fields to `match_all` or `match_none` without disk I/O.

## Practical Usage Patterns

Understanding the implementation details guides proper field selection and query construction.

### Full-Text Search with Match Query

Use the `match` query when searching analyzed text fields like article titles, product descriptions, or log messages. The query automatically handles tokenization and normalization, allowing "Quick Brown Fox" to match documents containing "quick brown foxes" due to stemming and lowercasing.

```json
GET products/_search
{
  "query": {
    "match": {
      "description": {
        "query": "quick brown fox",
        "operator": "and",
        "fuzziness": "AUTO",
        "minimum_should_match": "75%"
      }
    }
  }
}

```

In this example, `MatchQueryBuilder` analyzes the input into individual tokens and constructs a Boolean query requiring all terms (`operator: and`) while allowing for minor misspellings (`fuzziness: AUTO`).

### Exact Value Filtering with Term Query

Apply the `term` query for precise filtering on keyword fields, status codes, user IDs, or enumerated values. Since `TermQueryBuilder` performs no analysis, the value must match the indexed term exactly, including case sensitivity (unless using the `case_insensitive` flag available since version 7.10).

```json
GET users/_search
{
  "query": {
    "term": {
      "status": {
        "value": "ACTIVE",
        "case_insensitive": true
      }
    }
  }
}

```

This query executes a verbatim comparison against the `status` keyword field. If the field were analyzed text instead of keyword, this query would likely return no results because the indexed terms would be individual words, not the full string "ACTIVE".

## Key Behavioral Differences

Several operational characteristics distinguish these queries beyond simple analysis.

### Multi-Term Handling

The `match` query naturally handles multi-word input by analyzing it into separate tokens and constructing a Boolean query. The `term` query accepts only a single value; to match multiple exact values, you must use a `terms` query or combine multiple `term` clauses within a `bool` query.

```json
GET orders/_search
{
  "query": {
    "bool": {
      "should": [
        { "term": { "order_status": "PENDING" } },
        { "term": { "order_status": "SHIPPED" } }
      ],
      "minimum_should_match": 1
    }
  }
}

```

### Query Rewrites and Optimizations

Both builders implement rewrite logic to optimize execution. `MatchQueryBuilder.doIndexMetadataRewrite` detects when a field uses a `KeywordAnalyzer` and rewrites to a `TermQueryBuilder` for efficiency. Conversely, `TermQueryBuilder.maybeRewriteBasedOnConstantFields` rewrites queries against constant fields to `match_all` or `match_none`, eliminating unnecessary disk I/O.

### Fuzziness and Prefix Support

Only the `match` query supports fuzzy matching, prefix queries, and wildcard expansions through the `MatchQueryParser`. The `term` query provides no fuzzy capabilities; exact byte-matching is the only mode of operation, though the `case_insensitive` parameter allows for case-normalized exact matching on keyword fields.

## Summary

- **Use `match` queries** for full-text search on analyzed fields like `text` types, where you need tokenization, stemming, relevance scoring, and support for fuzzy matching.
- **Use `term` queries** for exact-value filtering on `keyword`, numeric, or other non-analyzed fields, where the value must match verbatim without analysis.
- **Remember the analysis layer**: `MatchQueryBuilder` processes input through the field's analyzer via `MatchQueryParser`, while `TermQueryBuilder` in [`server/src/main/java/org/elasticsearch/index/query/TermQueryBuilder.java`](https://github.com/elastic/elasticsearch/blob/main/server/src/main/java/org/elasticsearch/index/query/TermQueryBuilder.java) creates a Lucene `TermQuery` with no analysis.
- **Handle multiple values correctly**: Use `bool` queries with multiple `term` clauses or a `terms` query for exact matching against multiple values, since `term` queries only accept single values.

## Frequently Asked Questions

### Can I use a match query for exact matches?

You can, but only if the field uses a `keyword` analyzer or is a `keyword` field type. In `MatchQueryBuilder.doIndexMetadataRewrite`, the builder automatically rewrites to a `TermQueryBuilder` when it detects a `KeywordAnalyzer`, effectively performing an exact match. However, for `text` fields, a `match` query will analyze the input and potentially match multiple documents due to tokenization, making it unsuitable for precise exact matching.

### Why does my term query return no results on text fields?

A `term` query performs no analysis on the input value, comparing it verbatim against the indexed terms. When you apply a `term` query to an analyzed `text` field, the indexed terms are typically individual words (tokens) that have been lowercased and stemmed. If you search for "Quick Brown Fox" using a `term` query, it looks for that exact string including capitalization and spaces, which won't match the indexed tokens "quick", "brown", and "fox". Use a `match` query for `text` fields instead.

### When should I use a terms query instead of term query?

Use a `terms` query when you need to match a single field against multiple exact values and want cleaner syntax than a `bool` query with multiple `term` clauses. While combining multiple `term` queries in a `bool` query's `should` clause works for OR logic, a `terms` query is more concise for matching any of a list of values. Additionally, `terms` queries can be more efficient for large lists of values as they reduce query parsing overhead and leverage specific optimizations in the Lucene `TermInSetQuery`.

### Does case_insensitive work on all field types?

No, the `case_insensitive` parameter only works on `keyword` fields and certain other string-based field types that support normalization. As implemented in `TermQueryBuilder.doToQuery`, the parameter triggers a case-insensitive term query only when the field mapper supports it. For `text` fields or numeric fields, the `case_insensitive` flag has no effect because `text` fields are analyzed (where case handling happens at index time via analyzers) and numeric fields have no case concept. Always ensure your mapping uses the `keyword` field type if you need case-insensitive exact matching with the `term` query.