100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Elasticsearch

Filtering vs Scoring

Why the choice between filter context and query context is a core Elasticsearch performance and relevance decision, not just a syntax preference.

SearchingIntermediate8 min readJul 10, 2026
Analogies

Two Different Questions

Every clause you write ultimately answers one of two different questions. Filtering answers 'does this document qualify at all?' — a strict, binary yes/no with no notion of degree, appropriate for structured constraints like tenant_id, status, or a date range. Scoring answers 'given that this document qualifies, how relevant is it?' — a continuous, comparative measure produced by a similarity algorithm, appropriate for free-text relevance like how well a product description matches a shopper's search terms. Conflating the two is a common design mistake: putting a category filter into a scored must clause means two equally category-matching documents can end up with different scores purely due to term frequency noise from that filter, muddying the ranking signal that should come from the actual text relevance.

🏏

Cricket analogy: Filtering is like checking whether a player is even eligible to be selected — Indian passport holder, under-19 — a strict yes/no, while scoring is like ranking eligible players by batting average, a continuous comparative measure applied only after eligibility is confirmed.

Performance Impact: Caching and Cost

Filter context clauses are executed by Lucene and their results are frequently cached as bitsets in the filter cache, meaning a repeated filter like status: active or a common date range can be served near-instantly on subsequent requests without re-scanning the index. Query context clauses, by contrast, must compute a fresh score contribution for every matching document on every request, since scoring can depend on statistics like term frequency across the current index segment, and Elasticsearch does not cache scored results the same way. This means that moving a static, frequently repeated condition from must into filter is often the single highest-leverage performance optimization available for a slow search endpoint, especially at high query volume where the same filter values recur across many different users' requests.

🏏

Cricket analogy: A cached filter is like a stadium's pre-checked season-ticket list — once verified, the gate scans instantly on repeat visits — while scoring is like a fresh performance review computed anew for every single match, never reused.

json
// Slower: category placed in must, contributes noisy score contribution
{ "query": { "bool": { "must": [
  { "match": { "description": "wireless headphones" } },
  { "term": { "category.keyword": "electronics" } }
] } } }

// Faster and cleaner: category moved to filter, cached and unscored
{ "query": { "bool": {
  "must": [ { "match": { "description": "wireless headphones" } } ],
  "filter": [ { "term": { "category.keyword": "electronics" } } ]
} } }

The filter cache stores bitsets per index segment and is automatically evicted under memory pressure using an LRU policy, so there is no manual cache management required — you only need to make sure the clause is placed in filter context to be eligible for caching.

When Scoring Should Include a 'Filter-Like' Condition

The rule of thumb isn't absolute: sometimes a condition that looks like a filter should actually influence ranking. A should clause checking whether a document's brand field equals a shopper's favorite brand is technically an exact-match condition, but placing it in should rather than filter is correct because you want it to boost relevant results, not exclude non-matching ones. The deciding question is always 'should this condition change whether a document is included, or how it's ranked among included documents?' — conditions that gate inclusion belong in filter/must_not, and conditions that should nudge relative order among already-included results belong in must/should, regardless of whether the underlying clause type is term, match, or range.

🏏

Cricket analogy: A should clause on 'has captaincy experience' is like a selector using leadership history as a tiebreaker to rank otherwise-eligible players higher, not as a hard requirement that disqualifies anyone lacking it.

Don't default every exact-match condition into filter reflexively — if the condition is meant to influence relative ranking rather than gate inclusion, it belongs in should or must, even though it uses a term or range clause under the hood.

  • Filtering answers a binary inclusion question; scoring answers a continuous relevance question.
  • Filter context clauses run in filter/must_not and are cacheable as Lucene bitsets.
  • Query context clauses run in must/should and compute a fresh score contribution every request.
  • Moving static, repeated conditions from must to filter is a high-leverage performance optimization.
  • The filter cache uses per-segment bitsets with automatic LRU eviction under memory pressure.
  • Some exact-match conditions belong in should when they're meant to rank rather than exclude.
  • The deciding question is whether a condition should gate inclusion or influence relative order.

Practice what you learned

Was this page helpful?

Topics covered

#Elasticsearch#ElasticsearchStudyNotes#Database#FilteringVsScoring#Filtering#Scoring#Two#Different#StudyNotes#SkillVeris