Chapter 6 of 10
Hybrid candidate generation and rank fusion
Implementation
About 4 minutes · includes examples, an exercise, and references
Chapter at a glance
- •Union candidates by stable identity and preserve every component rank and score.
- •RRF fuses ranks without pretending raw component scores are comparable.
- •Candidate depths are budgets chosen through marginal recall and cost.
Hybrid retrieval combines systems whose errors are not perfectly correlated. A lexical retriever catches exact terms, codes, and names. A dense retriever catches paraphrases and conceptual relations. Learned sparse or late-interaction retrievers contribute other evidence. The objective is not to average everything; it is to improve recall and rank on defined query slices while keeping latency, cost, and behavior understandable.
Start by running retrievers independently and unioning candidates by stable passage identity. Retain rank and raw score from each source. A document absent from one list is missing evidence, not necessarily a zero on the other model’s scale. Component scores often have incompatible distributions. BM25 scores vary with query terms and collection statistics; cosine values depend on the embedding model; learned scores may be logits. Naive weighted addition without calibration can let one component dominate unpredictably.
Reciprocal Rank Fusion avoids raw score calibration. For each candidate d, sum 1/(k + rank_r(d)) across retrievers r. The constant k reduces the impact of very high ranks and controls how much deeper list positions contribute. A candidate ranked well by several systems rises; a candidate rescued by one system still enters the union. RRF is simple and robust, but it discards score margins. Tune k and candidate depths on judged queries, and retain component traces.
Score fusion can be appropriate when calibrated. Options include per-query min-max normalization, z-scores, learned logistic calibration, or a learning-to-rank model using component scores and query features. Each has risks. Min-max is sensitive to outliers and list truncation. Z-scores assume a useful distribution. Learned fusion can overfit domains or query mixes. Train and evaluate with temporal splits where possible, because query and corpus distributions evolve.
Query routing can reduce cost. An exact quoted identifier may rely heavily on lexical search; a natural-language conceptual question may allocate more dense candidates; an empty or unsupported query may return guidance instead of searching. Routing should be a measurable policy, not an opaque shortcut. Log route features and compare against an always-run baseline to quantify saved cost and missed recall.
Filters must be applied consistently. If both indexes support authorization and version filters, apply them within candidate generation. If one cannot, do not expose its unauthorized candidates to later stages or logs. Divergent analyzers and document generations create confusing unions, so every result should carry corpus and representation versions. Deduplicate by canonical search-unit identity, not normalized text alone; identical text in two authorized sources may have different provenance.
Candidate depth is a budget. Increasing lexical and dense k can raise recall but increases ANN work, union size, network transfer, and reranking cost. Allocate depth by measured marginal gain. Plot candidate recall as each source depth grows, then inspect overlap. If two retrievers return nearly identical sets, the second may add little. If a critical slice relies entirely on one retriever, protect it with a release gate.
Hybrid debugging is a stage ledger. For a query and judged relevant unit, record whether it existed in the published corpus, passed filters, appeared in each candidate list, survived union and deduplication, received each fusion contribution, entered reranking, and appeared in the final list. This turns “hybrid search feels worse” into a localized defect.
At toy scale, two short ranked lists make RRF transparent. At application scale, support search unions BM25 identifiers with semantic symptoms, reranks the top forty, and returns five distinct articles. At system scale, a federated service queries regional lexical and vector shards, enforces tenant policy locally, fuses only compatible evidence, and declares partial coverage when a shard fails. The same fusion equation is the easy part; identity, policy, versioning, and observability make it reliable.
Release a hybrid system only after an ablation study. Compare lexical only, dense only, union without reranking, fusion variants, and the complete pipeline. Report overall metrics, slices, latency, cost, and confidence intervals. Complexity is justified when a component rescues important cases without unacceptable regression elsewhere.
Key points
- Union candidates by stable identity and preserve every component rank and score.
- RRF fuses ranks without pretending raw component scores are comparable.
- Candidate depths are budgets chosen through marginal recall and cost.
- A stage ledger should localize every relevant item lost by the pipeline.
Reciprocal Rank Fusion
Read the expected behavior in the surrounding walkthrough, then copy and run this reference implementation.
from collections import defaultdict
def rrf(rankings, k=60):
scores = defaultdict(float)
evidence = defaultdict(dict)
for source, document_ids in rankings.items():
unique_ids = dict.fromkeys(document_ids)
for rank, document_id in enumerate(unique_ids, start=1):
contribution = 1.0 / (k + rank)
scores[document_id] += contribution
evidence[document_id][source] = {"rank": rank, "rrf": contribution}
ordered = sorted(scores, key=lambda item: (-scores[item], item))
return [(item, scores[item], evidence[item]) for item in ordered]
lists = {"lexical": ["d1", "d3", "d2"], "dense": ["d2", "d3", "d4"]}
for item in rrf(lists): print(item)Worked examples
Toy
Fuse two ranked lists
Lexical and dense search each return three passages with one overlapping result.
Union identities, compute reciprocal-rank contributions, and inspect why the shared candidate rises.
- Missing rank differs from a zero raw score.
- Ties have a deterministic rule.
- Component evidence survives fusion.
Application
Support knowledge search
Exact error codes and narrative symptoms occur in the same query stream.
Allocate candidates to BM25 and dense retrieval, fuse, rerank, diversify by article, and evaluate exact-code and paraphrase slices separately.
- Critical exact-code recall never regresses.
- Candidate depth follows marginal gain.
- Reranking cost is bounded.
System
Federated regional retrieval
Indexes are distributed by tenant and residency region.
Authorize and retrieve locally, attach generation and coverage metadata, fuse at a coordinator, and mark results incomplete after shard failure.
- Unauthorized identities never reach the coordinator.
- Partial coverage is explicit.
- Scores from incompatible generations are not merged silently.
Exercise
Run a fusion ablation
Evaluate lexical, dense, and hybrid retrieval on a mixed query set.
- Implement RRF with evidence and deterministic ties.
- Sweep component depths and k, measuring recall, nDCG, latency, and reranking volume.
- Report wins and regressions for identifier, paraphrase, temporal, and filtered slices.
Success criteria
- The complete hybrid system beats both components on declared critical metrics.
- No conclusion relies on incomparable raw scores.
- Every lost judged item is localized to a stage.
Reflect: Which retriever adds unique relevant candidates rather than duplicate work?
References and further reading
- Reciprocal Rank Fusion Outperforms Condorcet and Individual Rank Learning MethodsThe primary paper introducing and evaluating Reciprocal Rank Fusion.
- Dense Passage Retrieval for Open-Domain Question AnsweringThe primary DPR dual-encoder paper.
- SPLADE v2: Sparse Lexical and Expansion Model for Information RetrievalThe primary SPLADE v2 learned sparse retrieval paper.