NEW

Pulse 2025 Product Roundup: From Monitoring to AI-Native Control Plane

Elasticsearch dis_max Query: Best-Field Scoring Across Fields - Syntax, Example, and Tips

The Elasticsearch dis_max (disjunction max) query takes a set of sub-queries and returns documents matching at least one. Its scoring uses only the highest-scoring sub-query, optionally blended with the others via a tie_breaker. It works on any field type that the wrapped sub-queries support. Use dis_max when the same user input is run against several fields and the right answer is "score by the single best field", not "sum scores across fields".

Syntax

{
  "query": {
    "dis_max": {
      "queries":     [ /* sub-queries */ ],
      "tie_breaker": 0.0,
      "boost":       1.0
    }
  }
}

Parameters

Parameter Type Default Description
queries array - One or more sub-queries (any DSL clause). At least one is required.
tie_breaker float 0.0-1.0 0.0 Fraction of non-max sub-query scores added to the max. 0.0 = pure best-field; higher values reward documents that match multiple sub-queries.
boost float 1.0 Multiplier on the final score.

multi_match with type: best_fields (the default) is internally rewritten to a dis_max. Use dis_max directly when the per-field sub-queries differ in shape (different analyzers, different fuzziness, mixing match and match_phrase, etc.).

Examples

Best-field search across title, body, and tags:

GET /articles/_search
{
  "query": {
    "dis_max": {
      "queries": [
        { "match": { "title": "elasticsearch guide" } },
        { "match": { "body":  "elasticsearch guide" } },
        { "match": { "tags":  "elasticsearch guide" } }
      ],
      "tie_breaker": 0.3
    }
  }
}

Mix query types per field - match_phrase on title for higher weight, match on body for recall:

GET /articles/_search
{
  "query": {
    "dis_max": {
      "queries": [
        { "match_phrase": { "title": { "query": "distributed search", "boost": 3 } } },
        { "match":        { "body":  "distributed search" } }
      ],
      "tie_breaker": 0.2
    }
  }
}

Inside a bool - filter on category, score by best-field across language-specific fields:

GET /docs/_search
{
  "query": {
    "bool": {
      "filter": [ { "term": { "category": "search" } } ],
      "must": [
        { "dis_max": {
            "queries": [
              { "match": { "body.english":   "running shoes" } },
              { "match": { "body.spanish":   "running shoes" } },
              { "match": { "body.shingles":  "running shoes" } }
            ],
            "tie_breaker": 0.1
        }}
      ]
    }
  }
}

Performance and Use Notes

Each sub-query runs independently and the engine takes the max. Cost is roughly the sum of sub-query costs. dis_max is cheap when the inner clauses are cheap (term, match against keyword), and inherits whatever overhead the inner clauses have (phrase positions, fuzzy expansion, wildcards).

tie_breaker is the key tuning knob. With 0.0, score equals the single highest sub-query score; documents that match two fields look identical to documents that match only one. With 1.0, scores sum and dis_max behaves like a bool.should. Typical production values are 0.1-0.3: prefer the best field but reward multi-field matches a little.

When the per-field sub-queries are structurally identical, multi_match is shorter, easier to maintain, and produces the same plan. Pick dis_max only when sub-queries diverge in shape.

Multi-field scoring choices have outsized impact on perceived search quality. Pulse inspects Elasticsearch query patterns and surfaces dis_max/multi_match configurations where tie_breaker choice is inconsistent with relevance goals - useful when relevance regressions need triage without rebuilding indexes.

Common Mistakes

  1. Setting tie_breaker: 1.0 and effectively replacing dis_max with bool.should - the disjunction-max property is lost.
  2. Forgetting that dis_max is a scoring query; placing it in bool.filter discards score and removes the entire benefit.
  3. Mixing fields of very different lengths without per-clause boost - the longer field dominates pure-BM25 scoring and dis_max keeps picking it.
  4. Using dis_max with one sub-query - it is a no-op wrapper; remove it.
  5. Reaching for dis_max when multi_match with type: best_fields would express the same thing more concisely.

Frequently Asked Questions

Q: How does the dis_max query differ from a bool should query?
A: bool.should sums scores from every matching clause; dis_max takes the maximum score and optionally adds a tie_breaker * sum_of_others. Use dis_max when the right answer is "score by the best field", not "score by total signal across fields".

Q: What does tie_breaker control in a dis_max query?
A: tie_breaker is the fraction (0.0-1.0) of non-max sub-query scores added to the max. 0.0 is pure best-field. 1.0 is equivalent to summing all sub-query scores. Production setups typically use 0.1-0.3.

Q: When should I use dis_max instead of multi_match?
A: Use dis_max directly when the per-field sub-queries differ in shape - different query types, different analyzers, different fuzziness. When every field gets the same match clause, multi_match with type: best_fields is the shorter form and compiles to the same dis_max plan internally.

Q: Does dis_max support filters?
A: No, not as a direct parameter. Filters should be applied by wrapping dis_max inside a bool query and placing term/range clauses in bool.filter.

Q: Can dis_max be combined with function_score?
A: Yes. Wrap the dis_max clause inside a function_score query as the inner query, then apply functions (decay, popularity, script_score) on top of the best-field score.

Q: Why are my dis_max results dominated by one field?
A: Usually because that field has shorter documents and BM25 favors short fields, or because per-clause boost skews the comparison. Inspect with "explain": true to see each sub-query's contribution, then adjust per-field boost values.

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.