When do should clauses in an Elasticsearch bool query affect which documents match?
answer
- Optional by default, but not always
- One parameter decides the answer
- Its default is contextual, not fixed
- Presence of must or filter flips it
- Defaults to 1 alone, 0 alongside must
basics
~20 sOnly when minimum_should_match requires it. If the bool query has at least one should clause and no must or filter clauses, minimum_should_match defaults to 1; otherwise it defaults to 0, so should clauses only add to _score.
solid answer
~40 sIt depends on `minimum_should_match`, whose default is contextual. If the `bool` query contains at least one `should` clause and **no** `must` or `filter` clause, the default is 1 — so at least one `should` must match, and the query behaves like an OR. As soon as there is a `must` or `filter` clause, the default drops to 0: the `should` clauses become purely optional and only add a scoring contribution for the ones that happen to match. That is the trap — people add `should` clauses next to a `must` expecting them to narrow the result set, and instead only the ranking moves. Setting `minimum_should_match` explicitly overrides the default in both directions, and it accepts an integer, a negative integer, a percentage such as `"75%"`, a negative percentage, or a conditional combination like `"3<90%"`.
code
json · 8 lines{
"query": {
"bool": {
"must": [ { "match": { "title": "laptop" } } ],
"should": [ { "term": { "brand": "acme" } } ]
}
}
}go deeper
Recall that should means optional and that a bool query built only from should clauses behaves like an OR requiring one match. Knowing the parameter's name is enough at this stage.
State the contextual default precisely — 1 with no must or filter present, 0 otherwise — and show the classic bug where a should clause next to a must only reranks instead of filtering.
Demonstrate the regression story: adding a permissions filter silently flips the default and widens the result set. Argue for setting minimum_should_match explicitly whenever should clauses carry selection meaning.
Own the query-construction convention across services: which signals are hard predicates, which are optional boosts, and how minimum_should_match is parameterised so short and long user inputs both behave sensibly.
## What should means Inside Elasticsearch's `bool` query, the `should` array holds **optional** clauses. A document does not have to match them — but each one it *does* match adds its scoring contribution to `_score`. That makes `should` the natural home for "nice to have" signals: a synonym, an alternative field, a preferred category. The question interviewers actually ask is the boundary case: *do should clauses ever become required?* The answer lives in one parameter. ## The contextual default of minimum_should_match `minimum_should_match` sets how many `should` clauses a document must match. Its default is **not** a fixed number: - If the `bool` query has at least one `should` clause and **no `must` and no `filter` clause**, the default is **1**. The query is a plain OR over the should clauses. - Otherwise — that is, whenever a `must` or `filter` clause is present — the default is **0**. The should clauses are purely optional and contribute score only. Note what is *not* in that rule: `must_not`. A `must_not` clause is an exclusion, not a positive selector, so a `bool` containing only `must_not` and `should` still falls under the first case and requires one `should` to match. ## The classic bug ```json { "bool": { "must": [ { "match": { "title": "laptop" } } ], "should": [ { "term": { "brand": "acme" } } ] }} ``` The author's intent is often "laptops, and only Acme ones". What they built is "laptops, with Acme ones ranked higher" — every other brand is still in the result set. Because `must` is present, `minimum_should_match` defaulted to 0. The two possible fixes express two different intents: - If the brand is a hard requirement, it belongs in `filter` (or `must`), not `should`. - If it is a preference but at least one preference must hold, set `"minimum_should_match": 1` explicitly. The mirror-image bug is the other direction: a query built entirely from `should` clauses, to which someone later adds a `filter` for permissions. The day that filter is added, `minimum_should_match` silently flips from 1 to 0 and the query starts matching every permitted document in the index, ranked by how many should clauses they hit. That regression is invisible in unit tests that only assert the top hit. The defence is to always set `minimum_should_match` explicitly when should clauses carry selection meaning. ## The accepted formats `minimum_should_match` is more expressive than a plain count: - **Positive integer** (`3`) — at least that many should clauses must match. If it exceeds the number of should clauses, nothing matches. - **Negative integer** (`-1`) — all but that many must match; tolerant of one miss. - **Percentage** (`"75%"`) — that share of the should clauses, rounded down. With four clauses, `"75%"` requires three. - **Negative percentage** (`"-25%"`) — that share may be missing. - **Combination** (`"3<90%"`) — if there are 3 or fewer clauses all are required; above that, 90% of them. This shape is what makes short and long inputs behave sensibly under one setting. A percentage that computes to zero still requires at least one clause to match when the bool has no must or filter, because the contextual default floor applies. ## Scoring, not just matching Even when should clauses are optional, they are running in **query context**, so each matching one costs scoring work and adds to `_score`. A document that matches three should clauses outranks one that matches a single clause, because the contributions are summed. That summing is deliberate here — it is precisely what `dis_max` exists to avoid when the clauses are alternative views of the *same* text across several fields. Because they are scored, a long `should` array is not free. Twenty optional clauses mean twenty postings lists to open and twenty score contributions per candidate document. If the clauses are exact-value signals that should only nudge ranking, wrapping each in `constant_score` keeps the cost predictable and stops term statistics from making a rare brand outrank a good title match. ## Answering the interview version A complete answer covers four beats: should is optional by default; the default of `minimum_should_match` depends on whether a must or filter clause is present; setting it explicitly is the fix for both directions of the bug; and even optional should clauses always cost scoring work and shift ranking. Mentioning that a later-added filter can silently change matching semantics is what marks a candidate who has debugged this in production rather than read about it.
- A query built from three should clauses starts returning far too many hits after someone adds a filter clause for permissions. What happened?Adding the filter flipped minimum_should_match's default from 1 to 0. The three should clauses stopped being a required OR and became pure scoring signals, so every permitted document now matches and the result set explodes. The fix is to set minimum_should_match to 1 explicitly, which makes the query's intent independent of what other clauses are present.
- With four should clauses and minimum_should_match set to "75%", how many must match?Three. The percentage is applied to the number of should clauses and rounded down, so 75% of four is three. Percentages are useful when the clause count varies with the user's input; a fixed integer would be too strict for short inputs and too lenient for long ones.
- If should clauses are optional, do they still cost anything?Yes. They run in query context, so each one opens its postings list and computes a score contribution for every candidate it matches, and the contributions are summed into _score. A long should array is real CPU per query, and it changes ranking even when it changes nothing about matching.
- Does adding a must_not clause change the default of minimum_should_match?No. The rule keys off must and filter clauses only. A bool query holding just must_not and should clauses still has no positive required selector, so the default stays at 1 and at least one should clause must match.
saying these in an interview costs you the question
- Says should clauses always narrow the result set
- Thinks minimum_should_match defaults to 1 in every bool query
- Adds a should clause expecting it to act as a required filter
- Believes must_not counts as a must for the default rule
- Claims optional should clauses cost nothing when they do not match