C.W.K.
Stream
Lesson 03 of 05 · published

Vectors and RRF

~13 min · vectors, rrf, fusion, hybrid, embeddings

Level 0Unlit Wick
0 XP0/33 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"Keyword search finds the words you typed. Vector search finds the meaning you meant. Fusion is how you stop choosing between them."

What Vectors Add

An embedding model turns a piece of text into a point in a high-dimensional space — Lantern uses one that produces a 1024-dimensional vector. The magic property: texts that mean similar things land near each other, even when they share no words. Search "how do I keep my cool under market panic" and vector search can surface a passage about "emotional discipline during a crash," which BM25 would miss entirely because not one keyword overlaps. Vectors retrieve by meaning, and that's exactly the case keyword search is blind to.

The Fusion Problem

So now you run both and you have two ranked lists: BM25's keyword hits and the vector store's semantic hits. You want one merged ranking. Here's the trap: their scores live on incomparable scales. A BM25 score and a cosine similarity aren't the same kind of number — you can't just add them, and normalizing them into a shared range is fiddly, brittle, and needs constant re-tuning as your data shifts. Naive score blending is where hybrid search quietly goes wrong.

RRF: Fuse by Rank, Not Score

Reciprocal Rank Fusion sidesteps the whole mess with one idea: ignore the scores, use only the rank positions. Each result gets, from every list it appears in, a contribution of 1 / (k + rank), where rank is its position in that list and k is a small constant (60 is the well-worn default). Sum those contributions across lists and sort. A document ranked #1 in either list scores well; a document ranked highly in both scores best of all. No score normalization ever happens, because scores never enter the math.

When combining rankings, fuse on rank, not on raw score. Different retrieval methods produce scores on scales that were never meant to be compared. Rank position, by contrast, is universal — being 3rd means the same thing in any list. RRF turns 'combine these incomparable systems' from a tuning nightmare into a two-line, parameter-light function that just works. It's one of the highest value-to-complexity ratios in all of retrieval.

Why This Beats Clever Score Math

You could try to learn optimal weights, calibrate score distributions, or train a fusion model. RRF asks: why? It has essentially one parameter, needs no training, is robust to wildly different score scales, and empirically holds its own against far fancier methods. That combination — nearly free, nearly parameterless, hard to break — is why it's the default fusion in serious hybrid engines. The vector half also needs the embedding server, so when that's down, hybrid degrades to keyword-only and says so; RRF just fuses whatever lists it was handed.

Code

RRF in full — fuse two rankings without ever comparing their scores·python
def reciprocal_rank_fusion(ranked_lists: list[list[str]], k: int = 60) -> list[str]:
    """Fuse several ranked lists of chunk_ids into one — by RANK, never by score."""
    scores: dict[str, float] = {}
    for lst in ranked_lists:                 # e.g. [bm25_ids, vector_ids]
        for rank, chunk_id in enumerate(lst, start=1):
            scores[chunk_id] = scores.get(chunk_id, 0.0) + 1.0 / (k + rank)
    # Highest fused score first. Appearing high in BOTH lists wins.
    return sorted(scores, key=scores.get, reverse=True)

# Note what never appears: no BM25 score, no cosine similarity, no normalization.
# The two systems' scores were incomparable — so we simply never compared them.
fused = reciprocal_rank_fusion([bm25_hits, vector_hits], k=60)

External links

Exercise

Write two short ranked lists by hand — imagine a keyword search and a vector search returning five results each for the same query, with some overlap and some unique hits. Apply RRF with k=60 on paper: give each result 1/(60+rank) from each list it appears in, sum, and re-sort. Notice which results rise: the ones that both methods liked. That emergent agreement is the whole value of fusion.
Hint
A result that appears in only one list gets a single 1/(60+rank) term; a result in both lists gets two terms added together. That's why items both retrievers agree on float to the top — they're the ones two independent methods both vouched for.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.