Rescore #
rescore re-ranks the top window of hits with a second query — an
expensive precision pass (phrase, vector similarity, a narrow filter
match) applied only where it can change the final page, instead of to
every matching document.
POST /my-collection/_search
How it works #
Rescore is engine-native. When a request carries a rescore block, the
collector widens its gather to max(from + size, window) candidates, the
first-pass query ranks them, and the store layer then applies the rescore
to the collected set (apply_rescore_to_result in
lib/engine/src/store/layered/generic_reader.rs, blending in
lib/engine/src/search/scorer/mod.rs):
- Each hit INSIDE the window is scored by the rescore query and blended:
new = query_weight × first_pass + rescore_query_weight × rescore. A window hit the rescore query does not match contributes 0 from the second term. - Hits OUTSIDE the window keep their first-pass score SCALED by
query_weight— the weight applies to the whole result set, not just the window. - The full list is re-sorted so the re-scored window interleaves with
the untouched tail, then truncated to
from + size.
The blend is always the weighted sum above — the internal scorer chain
also knows multiply/avg/max/min modes, but the request API
exposes only total. One rescorer per request: the native dialect is a
single object (the gateway rejects the array form with a 400).
Wire-form status: the ES-compatibility layer understands the
Elasticsearch shape (window_size plus a nested
query: {rescore_query, …} object), translates it to the native flat
dialect, applies only the FIRST rescorer of an array, and enforces the
validations — window below 10000, and collapse + rescore mutually
exclusive. Through the Pizza gateway itself, send the native form below;
the nested form is a parse error today, and the native path does not
(yet) reject the collapse mix.
Examples #
Lift the request-log needle out of a match-all haystack: every logs
document scores 1.0 on the first pass; the rescore adds three times the
search match score to the top 50 —
1.0 × 1.0 + 3.0 × 2.566 ≈ 8.70 for the strongest matches, so the 25
GET /search requests jump above the other 145.
Shrink the window to 2 and only the two leading hits get the treatment —
every other hit keeps 1.0 × query_weight. That boundary is the whole
point of the feature: pay for the expensive query on 2 or 50 documents,
never on all 150 (or 150 million).
Phrase precision on top of loose matching — base query wide, phrase rescore exact:
{
"query": { "match": { "field": "text", "query": "wood fired pizza" } },
"rescore": {
"window": 10,
"query": { "phrase": { "field": "text", "query": "wood fired" } },
"query_weight": 0.7,
"rescore_query_weight": 1.5
},
"size": 5
}
Use cases #
- Vector precision pass. Text match for recall, vector similarity over the top 10 for order — Stage 4 of the hybrid pipeline.
- Phrase tightening. Loose
matchrecall with aphraserescore so exact word order wins the top slots without punishing the recall underneath. - Boost a narrow signal. “Order by relevance, but let recent VIP activity win ties” — a filter-shaped rescore query over a small window is cheaper than scoring it for the whole corpus.
- Bandwidth-guarded reranking. Keep the window at or just above
from + size; anything larger spends second-pass score on hits the caller will never see.
Parameters for rescore
#
window
(Optional, integer, default:10) How many top hits to re-score. The collector gathers at leastmax(from + size, window)candidates.query
(Required, object) The rescoring query — any query type, executed over the window; its score is blended into each in-window hit.query_weight
(Optional, float, default:1.0) Weight of the first-pass score, for in-window blends and the outside-window scaling alike.rescore_query_weight
(Optional, float, default:1.0) Weight of the rescore query’s score.
Notes #
retrieve(hybrid) requests cannot carryrescore— the gateway rejects the mix; use Stage 4 only with a plainquery.score_functionsandrescorecompose freely on one plain query (functions shape the first-pass score, rescore then blends the second).- An all-
match_allpair makes the arithmetic easy to eyeball: base 1, rescore 1, so scores read as pure weights (5/15 in the conformance case above).
Related #
- Hybrid search pipeline — rescore is Stage 4 of the retrieve → fuse → score_functions → rescore chain.
- Sort and pagination — the other result-shaping half; rescore re-sorts by blended score, sort fixes the order outright.
- Field collapsing — the third member of the result-shaping family; the ES-compat layer rejects the collapse + rescore mix.
vectorquery — the usual resident of thequeryslot for similarity rescoring.