Real search boxes mix text relevance with filters, boosts and exclusions, all expressed through bool.
The bool query combines clauses:
must: must match and contributes to the score,filter: must match, no scoring, cacheable,should: optional matches that raise the score; if there is nomustorfilter, at least oneshouldmust match (minimum_should_matchcontrols this),must_not: excludes matches, runs in filter context.
A typical product search puts the user's text in must (a match or multi_match), structured conditions like category, price range and in-stock in filter, preferences in should (boost items on sale or from a favourite brand), and exclusions such as discontinued items in must_not.
This split between query context (how well does it match?) and filter context (does it match?) is central. Filters are faster, cached in the node query cache when used repeatedly, and don't distort relevance.
Bool queries nest, so you can express (A or B) and not C by putting a bool with two should clauses inside a filter. Use "boost" on individual clauses to weigh them. To debug why a document scored as it did, add "explain": true to the request or use the _explain API.
Example
GET /products/_search
{
"query": {
"bool": {
"must": [ { "multi_match": { "query": "gel pen", "fields": ["name^3", "description"] } } ],
"filter": [ { "term": { "category": "office" } },
{ "range": { "price": { "lte": 10 } } } ],
"should": [ { "term": { "on_sale": { "value": true, "boost": 2 } } } ],
"must_not": [ { "term": { "discontinued": true } } ]
}
}
}
# matches need the text in must and pass every filter;
# on_sale items rank higher; discontinued items never appearRemember
- must and should score; filter and must_not don't
- Put exact conditions in filter for speed, caching and clean relevance
- should boosts optional preferences
- bool queries nest to build any logic
Watch out for
- Putting exact filters in must, so they inflate scores and can't be cached as filters.