bool: filter and must_not — Query vs Filter Context
"Garden books under 20 that are in stock." Only one part of that sentence is about relevance — how well a title matches "garden". The price limit and stock flag are plain yes-or-no tests. Putting yes-or-no tests in the right place makes searches faster and rankings cleaner.
The rule
Ask "how well?" in query context; ask "yes or no?" in filter context.
Every clause runs in one of two contexts:
- Query context — "how well does this document match?" It computes a relevance
_score.mustandshouldrun here. - Filter context — "does it match, yes or no?" No score is computed, and Elasticsearch can cache the result, so repeated filters are cheap.
filterandmust_notrun here.
The two filter-context clauses:
filter— every query listed must match, but adds nothing to the score.must_not— any document matching a listed query is excluded.
GET /books/_search
{
"query": {
"bool": {
"must": [ { "match": { "title": "garden" } } ],
"filter": [ { "range": { "price": { "lt": 20 } } },
{ "term": { "in_stock": true } } ],
"must_not": [ { "term": { "genre": "hobby" } } ]
}
}
}Only the match affects ranking. Price, stock and genre just decide who gets in. If you moved the price range into must, the results would be the same set, but every score would shift by a meaningless bonus for "matching the price" — and the check could not be cached.
A bool with only filter clauses returns every hit with a score of 0 — the right choice when you just want "all fiction books", with order coming from sorting instead.
must_not is also how you negate other leaves, such as books with no price:
{ "query": { "bool": { "must_not": [ { "exists": { "field": "price" } } ] } } }The shortcut
For each condition ask "could a document match it better or worse?" If yes (words in text) → must or should. If it is simply true or false (prices, dates, flags, exact keywords) → filter, or must_not for exclusions.
"title about garden"
A title can match better or worse →
must.
Drills
Answer fast — trust the rule.
Which clause excludes matching documents?
What is the difference between putting a term query in must and in filter?
A bool query has only a filter clause. What score does each hit get?
Where should {"range": {"published": {"gte": "2020-01-01"}}} go if it is a strict requirement?
Remember
- Ask "how well?" in query context; ask "yes or no?" in filter context.
- must and should score; filter and must_not do not, and can be cached.
- Words in text → must or should; prices, dates, flags, exact values → filter or must_not.
