Learn · Search, Never Touch What Cannot Win
budding
The Score to Beat
Top-k search does not need every score. Once the answer set has a floor, a valid upper bound can prove that whole candidates are unable to enter it.
“program testing can be used very efficiently to show the presence of bugs, but never to show their absence.”
— Edsger W. Dijkstra, Concern for Correctness as a Guiding Principle for Program Composition (EWD 288, July 1970)
This is the tenth chapter in a book about search from first principles. You will derive the score-to-beat invariant, trace the WAND algorithm over sorted postings, prove that each cursor advance is safe, and distinguish an upper bound from an estimate. You will also see why tighter bounds are not automatically faster. The next chapter will turn that warning into an economic question: when does the saved scoring work repay the cost of proving a skip?
A race with two medals
Suppose a query needs the best two documents. The straightforward plan is:
- find every matching document;
- compute every exact score;
- sort the scores;
- retain the first two.
That plan is correct, but it answers a larger question than the user asked. To identify the best two, the engine does not need the exact ordering of everyone below second place.
Keep the two best scores seen so far in a min-heap. Once the heap is full, let
be its smallest score. This is the score to beat. A new candidate can enter the heap only by scoring at least ; after a deterministic tie-break, one can make the comparison strict, but the conservative version is enough here.
Top-k — the highest-ranked items under a stated ordering. A min-heap of size exposes the current kth score at its root, so a better candidate can replace it in time. Learn more.
The threshold alone saves nothing. We still need a cheap way to prove that a candidate cannot reach it.
A ceiling, not a guess
Assume the score is a sum of nonnegative query-term contributions:
For each query term , precompute a value such that
Then any candidate that can match only a subset of the query terms obeys
If that sum is below , exact scoring cannot change the top .
Upper bound — a value known to be at least as large as every value in its scope. It is a correctness contract, not a likely value. An overestimate loses pruning; an underestimate can lose the true winner. Broder and colleagues' WAND paper uses term-score upper bounds to guide evaluation.
Before continuing, decide which quantity may authorize a skip.
The license to skip is a proof obligation: the candidate's maximum possible score, under bounds that cover every omitted contribution, is below the current kth score.
Put the cursors on the corpus
Return to the eight documents introduced in The Back of the Book. Consider the disjunctive query
fox field index pages evidence
and suppose its scorer produces these nonzero contributions:
| Term | Postings as (document, contribution) | Bound |
|---|---|---|
| fox | (1, 2.0), (2, 1.5) | 2.0 |
| field | (1, 1.0), (2, 1.0) | 1.0 |
| index | (3, 1.5), (6, 1.2) | 1.5 |
| pages | (3, 1.4), (6, 1.1) | 1.4 |
| evidence | (5, 1.2), (7, 1.0) | 1.2 |
The exact nonzero document scores are therefore:
| Document | Score |
|---|---|
| 1 | 3.0 |
| 2 | 2.5 |
| 3 | 2.9 |
| 5 | 1.2 |
| 6 | 2.3 |
| 7 | 1.0 |
A full evaluation scores all six candidates. WAND keeps one cursor per postings list and repeatedly orders the cursors by their current document ID. It accumulates term bounds from left to right until their sum reaches . The cursor that crosses the threshold is the pivot.
WAND — “Weak AND,” a dynamic-pruning method introduced by Andrei Broder, David Carmel, Michael Herscovici, Aya Soffer, and Jason Zien. Its cursor and upper-bound test selects candidates for full evaluation without changing the exact result when the bounds are valid. Read the 2003 paper.
Here is the whole trace for . Before two results exist, take .
| Step | Ordered current documents | Decision | |
|---|---|---|---|
| 1 | fox 1, field 1, index 3, pages 3, evidence 5 | 0 | all cursors before the pivot agree on 1; score document 1 as 3.0 |
| 2 | fox 2, field 2, index 3, pages 3, evidence 5 | 0 | score document 2 as 2.5; heap fills, so |
| 3 | index 3, pages 3, evidence 5 | 2.5 | reaches the threshold at document 3; score 3 as 2.9 |
| 4 | evidence 5, index 6, pages 6 | 2.9 | evidence alone is bounded by 1.2; advance it to pivot 6, proving document 5 cannot win |
| 5 | index 6, pages 6, evidence 7 | 2.9 | reaches the threshold; score document 6 as 2.3 |
| 6 | evidence 7 | 2.9 | the remaining total bound is 1.2; stop, proving document 7 cannot win |
The answer is documents 1 and 3, exactly as full evaluation would report. Four candidates were scored and two were rejected by proof.
The pivot algorithm
The following form assumes increasing document IDs, additive nonnegative scores, valid per-term upper bounds, and a heap whose threshold is zero until it contains results.
WAND evaluation with term-level upper bounds
WAND-TOP-K(I, U, k)
Input: postings iterators I[1:m], valid bounds U[1:m], result count k
Output: the k highest-scoring documents under the exact additive scorer
H ← empty min-heap
while at least one iterator is not exhausted
order live iterators by their current document ID
θ ← 0 if H has fewer than k items, otherwise H.MIN-SCORE
bound ← 0
pivot ← NIL
for each iterator i in order
bound ← bound + U[i]
if bound ≥ θ
pivot ← i
break
if pivot = NIL
break
p ← pivot.CURRENT-DOCUMENT
if order[1].CURRENT-DOCUMENT = p
score ← 0
for each iterator i whose current document is p
score ← score + i.CURRENT-CONTRIBUTION
i.ADVANCE()
RETAIN-IF-TOP-K(H, (p, score), k)
else
order[1].ADVANCE-TO(p)
return H in descending result orderSorting cursors on every turn makes this presentation easy to inspect but is not the only implementation. The interesting operation is ADVANCE-TO(p): a postings iterator can seek to the first document ID at least , often using skip data. The algorithm's benefit depends on how many exact scores and postings advances it avoids, not on the spelling of the cursor container.
Why the advance is sound
The dangerous line is the one that advances the first iterator. It may jump over document IDs without scoring them. We need more than a successful trace.
At the start of each turn, order live iterators by current document ID. Let be the first pivot document, and let be the iterators before the pivot. By the definition of “first pivot,”
Now consider any document skipped when the first iterator advances to . Because , every iterator at or later is already past and cannot contain it. Thus can receive contributions only from iterators in . Validity of the bounds gives
So cannot enter the heap. Advancing past it preserves the top .
If no pivot exists, even the sum of every remaining bound is below . The same argument covers every unseen document, so termination is safe. If all iterators before the pivot already point to , the algorithm does not skip: it computes 's exact score and updates the heap. These cases exhaust every turn, which proves that the returned heap matches exhaustive evaluation.
What the proof costs
With query terms, exhaustive document-at-a-time evaluation visits the union of their postings and computes every candidate's exact score. The teaching algorithm adds cursor ordering and bound additions. If it re-sorts cursors each turn, that bookkeeping can cost per turn; practical variants keep the small cursor set ordered more carefully. The heap costs for an accepted replacement and space.
No single asymptotic expression promises a speedup. On the trace above:
| Work item | Exhaustive | WAND trace |
|---|---|---|
| exact document scores | 6 | 4 |
| candidates rejected by a bound | 0 | 2 |
| bound additions | 0 | 9 |
| heap capacity | 2 | 2 |
WAND paid nine cheap additions to avoid two exact scores. Whether that wins in time depends on the scorer, postings layout, bound tightness, cache behavior, and query. The next chapter measures this crossover instead of assuming it.
Four wrong turns
Treat a prediction as a bound
A learned model says a candidate will probably score 2.4. The threshold is 2.9, so the engine skips it. This is approximate retrieval, not WAND's exact contract: the candidate may really score 3.1. A prediction becomes a safe bound only with a separately proved error envelope that covers the candidate.
Round a bound downward
The true maximum contribution is 1.204, stored as 1.2 to save space. That tiny underestimate can invalidate the proof. Bounds must round outward. A looser 1.21 is safe and may skip less; 1.20 is unsafe if the contract is real-valued.
Freeze the initial threshold
At the start, , so almost nothing can be pruned. The useful threshold is the live kth score, which rises as better candidates arrive. Candidate order therefore affects work even though it must not affect the final answer.
Assume tighter is always faster
Per-block or per-impact bounds may reject more candidates, but reading and checking their metadata costs work. On short postings or homogeneous scores, the proof can cost more than the score it avoids. Correctness is monotone in bound looseness; performance is not monotone in bound detail.
Where the law stops
The proof above relies on additive nonnegative contributions and bounds that cover the exact scorer. Negative contributions, cross-term interactions, query-dependent features, and a later reranker need their own envelopes. One safe design retrieves a generous candidate set with bounded additive scores, then applies the unconstrained model only to those candidates. That preserves the first stage's theorem; it does not prove that the cascade equals ranking the entire collection with the later model.
MaxScore, introduced by Howard Turtle and James Flood, reaches the same broad goal with a different organization: terms whose maximum contributions cannot change the current top become nonessential. WAND and MaxScore should not be collapsed into one folklore algorithm. They are distinct ways to spend bounds against a threshold. The useful common abstraction is the proof obligation.
Lessons
- Top-k retrieval needs a threshold: the current kth score.
- A valid upper bound is a ceiling, not an estimate or average.
- Sorted postings prove that iterators at the pivot or later cannot contribute to earlier document IDs.
- An underestimate can change the answer; an overestimate only loses work.
- Dynamic pruning exchanges scoring work for proof work, so correctness alone does not establish a speedup.
Practice
- Retrieval. Without looking back, state the inequality that licenses a pre-pivot cursor advance.
- Discrimination. Give one quantity that predicts a score well but is not a valid upper bound.
- Trace. Set in the six-candidate table. Recompute every threshold, pivot, exact score, and skip.
- Repair. Suppose one query feature subtracts a penalty. State what must change in the bound before the proof applies.
- Transfer. Name a non-search top-k system. Identify its score to beat, an admissible upper bound, and the cost of checking that bound.
The remaining question is economic. This chapter proved that skipping is safe; it did not prove that skipping is cheap. The Arithmetic of Skipping asks when a finer proof refunds more work than it consumes.
References
- Broder, Carmel, Herscovici, Soffer, Zien. “Efficient Query Evaluation Using a Two-Level Retrieval Process.” CIKM 2003, 2003. — introduces WAND and its term-score upper-bound evaluation
- Turtle and Flood. “Query Evaluation: Strategies and Optimizations.” Information Processing & Management 31(6), 1995. — introduces MaxScore's organization of essential and nonessential terms
- Edsger W. Dijkstra. “Concern for Correctness as a Guiding Principle for Program Composition.” EWD 288, 1970. — primary source for the epigraph and its argument about what evidence can establish