Hybrid Search and Reciprocal Rank Fusion
Combine full-text and vector search for superior results — implement hybrid search patterns and use Reciprocal Rank Fusion (RRF) to merge ranked lists intelligently.
The best of both worlds
Imagine two talent scouts looking for the best footballer.
Scout A ranks players by statistics (goals, assists, pass accuracy). Scout B ranks players by watching them play (game intelligence, creativity, leadership). Each scout’s list is good, but combining them gives a better list than either alone. Hybrid search does the same: full-text search finds keyword matches, vector search finds semantic matches, and Reciprocal Rank Fusion (RRF) intelligently merges both lists into one final ranking.
How hybrid search works
User Query: "comfortable running shoes for flat feet"
│
┌───────────┴───────────┐
▼ ▼
Full-Text Search Vector Search
(keyword match) (semantic match)
│ │
1. Nike Flat Support 1. Brooks Adrenaline
2. ASICS Kayano 2. Nike Flat Support
3. Brooks Stability 3. New Balance 860
4. Saucony Guide 4. ASICS Gel-Kayano
│
└───────────┬───────────┘
▼
Reciprocal Rank Fusion
│
1. Nike Flat Support (in both lists!)
2. ASICS Kayano/Gel-Kayano (in both)
3. Brooks Adrenaline (top in vector)
4. Brooks Stability (keyword match)
Implementing hybrid search in SQL
-- Step 1: Full-text search results with ranking
SELECT ProductId, RANK as FTRank
INTO #FullTextResults
FROM CONTAINSTABLE(Products, Description, @searchTerms) ft;
-- Step 2: Vector search results with ranking
SELECT ProductId, ROW_NUMBER() OVER (ORDER BY distance) AS VecRank
INTO #VectorResults
FROM VECTOR_SEARCH(Products, 'DescriptionEmbedding', @queryVector, 50, 'cosine');
-- Step 3: Reciprocal Rank Fusion
WITH RRF AS (
SELECT
COALESCE(ft.ProductId, vs.ProductId) AS ProductId,
ISNULL(1.0 / (60 + ft.FTRank), 0) +
ISNULL(1.0 / (60 + vs.VecRank), 0) AS RRFScore
FROM #FullTextResults ft
FULL OUTER JOIN #VectorResults vs ON ft.ProductId = vs.ProductId
)
SELECT TOP 10 r.ProductId, p.Name, r.RRFScore
FROM RRF r
INNER JOIN Products p ON r.ProductId = p.ProductId
ORDER BY r.RRFScore DESC;
Reciprocal Rank Fusion explained
The RRF formula for each result:
RRF Score = sum of 1 / (k + rank) across all ranked lists
Where k is a constant (typically 60) that dampens the impact of high ranks.
Example calculation
| Product | Full-Text Rank | Vector Rank | RRF Score |
|---|---|---|---|
| Nike Flat Support | 1 | 2 | 1/(60+1) + 1/(60+2) = 0.0164 + 0.0161 = 0.0325 |
| ASICS Kayano | 2 | 4 | 1/(60+2) + 1/(60+4) = 0.0161 + 0.0156 = 0.0317 |
| Brooks Adrenaline | Not found | 1 | 0 + 1/(60+1) = 0.0164 |
| Saucony Guide | 4 | Not found | 1/(60+4) + 0 = 0.0156 |
Results in BOTH lists score highest. Nike Flat Support wins because it ranked well in both searches.
Exam tip: Why k = 60?
The constant k controls how much the rank position matters. With k = 60:
- Rank 1 gets score 1/61 = 0.0164
- Rank 2 gets score 1/62 = 0.0161
- The difference between rank 1 and rank 10 is small (0.0164 vs 0.0143)
This means RRF focuses more on which lists a result appears in rather than its exact position. A result at rank 5 in both lists beats a result at rank 1 in only one list. This is the correct behaviour for fusion — appearing in multiple search modalities is a stronger signal than ranking first in just one.
Evaluating hybrid search performance
| Metric | What to Measure | Hybrid vs Single |
|---|---|---|
| Precision@K | Are the top K results relevant? | Hybrid usually +10-20% over vector alone |
| Recall@K | Are all relevant results found? | Hybrid usually +5-15% over full-text alone |
| MRR (Mean Reciprocal Rank) | How high is the first relevant result? | Hybrid typically best |
| Latency | Total query time (both searches + fusion) | ~2x single search (run in parallel to minimise) |
Scenario: Leo optimises SearchWave's hybrid search
Leo at SearchWave compares three search approaches on 1,000 test queries:
- Full-text only: Precision@10 = 62%, MRR = 0.71
- Vector only: Precision@10 = 74%, MRR = 0.78
- Hybrid (RRF): Precision@10 = 83%, MRR = 0.89
Hybrid search improves precision by 9 points over vector alone and 21 points over full-text. The latency cost is minimal because Leo runs both searches in parallel (total time is the max of the two, not the sum).
Leo at SearchWave runs hybrid search but notices that some very relevant products only appear in vector results (not full-text) and get low hybrid scores. What should he adjust?
🎬 Video coming soon
Next up: RAG with SQL: Prompt, Process, Respond — build retrieval-augmented generation directly in your SQL database.