Elasticsearch Term Query: Exact-Value Match Without Analysis - Syntax, Example, and Tips

The Elasticsearch term query matches documents whose field contains the exact, unanalyzed value supplied. The query input is not run through any analyzer - it is compared byte-for-byte against the inverted index. It is the right tool for keyword, numeric, date, IP, and boolean fields. Using term against an analyzed text field is the single most common Elasticsearch query bug, because the indexed tokens rarely equal the raw input.

Syntax

{
  "query": {
    "term": {
      "<field>": {
        "value":            "<exact_value>",
        "case_insensitive": false,
        "boost":            1.0
      }
    }
  }
}

Shorthand: { "term": { "field": "value" } }.

Parameters

Parameter Type Default Description
value any - Exact value to match. Required.
case_insensitive bool false If true, lowercases both sides before comparing (7.10+).
boost float 1.0 Score multiplier when used in query context.

Examples

Exact match on a keyword field:

POST my-index/_search
{
  "query": {
    "term": { "status": { "value": "active" } }
  }
}

Filter context - cacheable, no scoring:

GET /events/_search
{
  "query": {
    "bool": {
      "filter": [ { "term": { "tenant_id": "acme" } } ]
    }
  }
}

Case-insensitive match (7.10+):

GET /users/_search
{
  "query": {
    "term": {
      "email": { "value": "alice@example.com", "case_insensitive": true }
    }
  }
}

Multi-value lookup - use terms instead:

GET /products/_search
{
  "query": {
    "terms": { "sku": ["sku-001", "sku-002", "sku-003"] }
  }
}

Performance and Use Notes

term is one of the cheapest queries in Elasticsearch. In filter context it produces a cacheable bitset reused across requests. Move every non-scoring exact-match clause into bool.filter. In query context it returns the BM25 score, which is rarely meaningful for keyword fields.

The distinction from match is purely about analysis. match runs the input through the field's analyzer; term does not. On a text field analyzed with standard, the indexed token for "Hello World" is [hello, world]. A term query for "Hello World" will not match, because the token "Hello World" does not exist. A match query against the same field would match. This trips up almost every team once.

Many production Elasticsearch slow-query reports trace to term queries against analyzed fields, returning empty results or unexpectedly wide ones depending on how the field is mapped. Pulse cross-references query patterns with field mappings on your Elasticsearch cluster and flags term/match mismatches, which usually means a field needs a keyword subfield or a query should be rewritten.

Common Mistakes

  1. Running term against a text field expecting it to match the literal string. Either query the .keyword subfield or switch to match.
  2. Forgetting that values are case-sensitive by default - "Active" does not equal "active" without case_insensitive: true or a lowercase normalizer on the field.
  3. Putting term in must (query context) when no score is needed; use filter for cacheable, faster execution.
  4. Using term for many values one at a time inside a bool.should; use terms query (one clause, internal optimization).
  5. Querying numeric fields as strings - { "term": { "price": "10" } } works due to leniency, but mixed types can mask data issues.

Frequently Asked Questions

Q: What is the difference between term query and match query in Elasticsearch?
A: The term query does not analyze the input and looks for an exact value in the inverted index. The match query runs the input through the field's analyzer first. Use term for keyword, numeric, date, and boolean fields; use match for full-text on text fields.

Q: Is the Elasticsearch term query case-sensitive?
A: By default, yes. Pass case_insensitive: true (Elasticsearch 7.10+) or define a normalizer on the field that lowercases values at index time. Note that case_insensitive only works on keyword and constant_keyword field types.

Q: Why does my term query return zero results on a text field?
A: Because text fields are analyzed and the raw input typically does not equal any indexed token. Either query the .keyword subfield (e.g. field.keyword), or use the match query, which will analyze the input.

Q: When should I use term query in filter context vs query context?
A: Always use filter context unless you need BM25 scoring from the clause - which is rare for exact-value matches. Filter context skips scoring and caches the resulting bitset across requests.

Q: How do I match multiple exact values in one query?
A: Use the terms query with an array: { "terms": { "status": ["active", "pending"] } }. It is optimized for multi-value lookup and produces a single cacheable bitset.

Q: Can the term query match on nested or object fields?
A: Object subfields work with dotted paths (user.id). True nested fields require a nested query wrapper to scope the term match to a single nested document.

Subscribe to the Pulse Newsletter

Get early access to new Pulse features, insightful blogs & exclusive events , webinars, and workshops.

We use cookies to provide an optimized user experience and understand our traffic. To learn more, read our use of cookies; otherwise, please choose 'Accept Cookies' to continue using our website.