Bool query (must / should / must_not / filter)
bool is the primary compound query: it combines leaf clauses with boolean logic across four occurrence types, each with distinct scoring and caching behavior.
Why it matters
Almost every non-trivial search is a bool tree — a scored full-text part AND a set of structured filters. Mastering which bucket a clause belongs in directly controls relevance, performance, and cache reuse; it is the single most important query in the DSL.
How it works
Four arrays, combined with AND/OR semantics.
| Occurrence | Logic | Context | Scores |
|---|---|---|---|
must | AND, required | query | yes |
filter | AND, required | filter | no (cached) |
should | OR, optional | query | yes |
must_not | AND NOT | filter | no (cached) |
shouldboosts, doesn’t gate — when at least onemust/filterexists,shouldclauses only add to_score; defaultminimum_should_matchis then 0.- No
must/filter, onlyshould—minimum_should_matchdefaults to 1, soshouldbecomes the required OR set. - Scores combine additively — total
_score= sum of matchingmust+shouldclause scores. filter/must_notare cached as bitsets per segment and cost no scoring.
Example
{ "bool": {
"must": { "match": { "desc": "running shoes" } },
"filter": [ { "term": { "brand": "acme" } },
{ "range": { "price": { "lte": 120 } } } ],
"should": [ { "match": { "color": "red" } } ], ← boost only
"must_not": [ { "term": { "discontinued": true } } ],
"minimum_should_match": 0 } }
Red shoes rank higher, but non-red still match because should is optional here.
Pitfalls
- Expecting
shouldto filter — when amustis present, an unmatchedshoulddoes not exclude the doc; setminimum_should_match: 1to force OR-gating. - Scoring structured constraints — putting
term/rangeinmustinstead offilterdrops caching and skews BM25. - Clause explosion — large
shouldlists can exceedmax_clause_count; collapse withtermswhere possible. - Nested
boolfor negation —must_notof ashouldgroup can double-negate unexpectedly; test with_explain.