Skip to content

RRF and weighted fusion

Intuition

When you run multiple sub-queries (title vector + body vector, or dense + FTS), each list has its own ranking. Reciprocal Rank Fusion (RRF) merges by rank, not raw score, so heterogeneous scorers combine cleanly. Weighted fusion scales per-field scores before aggregation.

Math

For a set of rankings \(Q\) and rank constant \(k\), RRF score of document \(d\):

\[ \mathrm{score}_{\mathrm{RRF}}(d) = \sum_{q \in Q} \frac{1}{k + r_q(d)} \]

where \(r_q(d)\) is the 1-based rank of \(d\) in list \(q\) (absent documents contribute nothing for that \(q\)).

Weighted fusion (schematic): each sub-query score \(s_q(d)\) is multiplied by weight \(w_q\) then aggregated under a fusion metric.

Illustration

flowchart TB
  q1["Sub-query 1"]
  q2["Sub-query 2"]
  l1["Ranked list 1"]
  l2["Ranked list 2"]
  fuse["RRF or Weighted"]
  out["Top-N fused hits"]
  q1 --> l1 --> fuse
  q2 --> l2 --> fuse
  fuse --> out

Citations

  • Cormack, Clarke, Buettcher, Reciprocal Rank Fusion outperforms Condorcet and individual Rank Learning Methods (SIGIR 2009)
  • Upstream hybrid / rerank docs: zvec.org

ZVec.NET mapping

Concern SDK
RRF type ZVecRrfReranker
Rank constant \(k\) RankConstant default 60 (ZVecDefaults.Rerank.RankConstant)
TopN Final fused count (0 = return all merged, per XML docs)
Weighted type ZVecWeightedRerankerWeights dictionary keyed by field name
Weight validation ZVecWeightedReranker.ValidateWeights — count must match sub-query count
API Multi-query Query([...], reranker: …) — requires ≥ 2 sub-queries
Guide Hybrid search and FTS

Group-by fusion paths remain blocked at the C API — see coverage.

See also