BM25
Scores documents by how often the query terms appear, discounted for common words and long documents. Exact, fast, blind to synonyms.
BM25 for exact terms, vectors for intent, a reranker to settle the order. We build hybrid retrieval that handles product codes, people's names and plain-language questions alike.
Pure semantic search is excellent at paraphrase and poor at exactness. Hybrid search exists for corpora where both matter.
You will see the gain when a meaningful share of queries contain things an embedding model blurs. Part numbers, ticket IDs, error codes, surnames, legal clause references, or a product name that differs from a near-identical one by a single character. You will also see it on mixed-language content, long-tail technical vocabulary, and documents where a single rare term is the whole point.
Scores documents by how often the query terms appear, discounted for common words and long documents. Exact, fast, blind to synonyms.
Embeds query and passages, returns the nearest neighbours. Handles paraphrase and intent, blurs codes and negation.
Reads the query and each candidate together and scores the pair. Slow per document, so it only sees the merged shortlist.
Each stage narrows the set. Retrievers are cheap and return many candidates. Fusion is free. The reranker is expensive per document, so it only sees the merged shortlist. This shape keeps latency flat while recall and precision both improve.
BM25 produces scores like 12.7; vector search produces similarities like 0.83. They are not on the same scale, and normalising them is fragile. Reciprocal rank fusion sidesteps the problem by ignoring scores and using positions.
Each list gives every document it contains a contribution of 1 ÷ (k + rank). A document found by both lists collects two contributions; a document found by one collects one. Add them up, sort by the total, and that is the fused order. The constant k dampens the gap between rank one and rank two; 60 is a widely used default and rarely needs changing.
The effect is intuitive. A document that is moderately good in both lists beats a document that is first in one and absent from the other. That is exactly what you want when one retriever is confidently wrong.
| Document | BM25 rank | Vector rank | RRF score (k = 60) | Fused rank |
|---|---|---|---|---|
| Returns policy | 3 | 1 | 1/63 + 1/61 = 0.0323 | 1 |
| Refund timelines | 2 | 4 | 1/62 + 1/64 = 0.0318 | 2 |
| Model 4471 spec sheet | 1 | not in list | 1/61 = 0.0164 | 3 |
Worked example with three documents. The spec sheet topped the keyword list but appears nowhere in the vector list, so two moderate placements beat it.
Retrievers compare a query to each document separately. A cross-encoder reads them together, which is why it catches negation, qualifiers and the difference between two similar products.
Takes each (query, passage) pair, produces a relevance score, and reorders the shortlist. It does not retrieve; it judges.
One model call per candidate. Rerank 20–50 passages, not 500. For chat-style interfaces this fits comfortably inside the time the LLM takes to answer.
Hosted rerank APIs from several model providers, or open-weight cross-encoders you run yourself. We choose based on data residency and latency, then confirm on your test set. See reranking.
| Store | Keyword side | Vector side | Fusion | Good when |
|---|---|---|---|---|
| PostgreSQL + pgvector | Built-in full-text search | pgvector index | In SQL or in the application | Content already lives in Postgres; modest scale |
| Milvus | Sparse vectors | Dense vectors | Multi-vector hybrid search in the engine | Large collections, self-hosted or managed |
| Qdrant | Sparse vectors | Dense vectors | Server-side fusion with payload filters | Heavy filtering, self-host control |
| Weaviate | Built-in BM25 | Dense vectors | Built-in hybrid query with a weighting parameter | Hybrid out of the box, module ecosystem |
| Existing search engine | Keep it | Add any vector store | In the application | A keyword engine is already tuned and trusted |
Product capabilities change often; we confirm the current behaviour of each engine during the selection sprint. The vector database selection guide covers the wider decision.
Label 100–300 real queries. Score the existing search, or a pure vector prototype, so every later change has a number to beat.
Stand up keyword and vector retrieval over the same chunks, with shared document IDs and metadata.
RRF first, then a reranker over the shortlist. Compare against weighted fusion on the test set.
Candidate counts, filters, chunk size and query rewriting, each judged by recall@k and MRR.
Shadow traffic, latency budget, dashboards and a feedback path from real queries into the test set.
Hybrid retrieval is also the retrieval layer we recommend for most enterprise RAG builds, where a missed passage becomes a wrong answer. If you are deciding how far to go, the RAG explained guide covers the trade-offs, and evaluating LLM outputs covers the measurement side.
The vector half of hybrid search, and when it is enough on its own.
ReadModel choice and chunking decide what either retriever can find.
ReadA short definition for colleagues who need the one-paragraph version.
DefineRetrieval is one layer; here is how we build the application around it.
ExploreHybrid retrieval across wikis, tickets and documents for internal teams.
ExploreSize the index and the monthly query bill before you commit.
Try the toolHybrid search runs a keyword retriever (usually BM25) and a vector retriever on the same query, merges the two result lists, and often passes the merged list through a reranker. It keeps exact matching for codes and names while adding meaning-based recall. See the glossary entry.
RRF is more robust because it only uses ranks, so you never have to reconcile BM25 scores with cosine similarities. Weighted score fusion can edge ahead when you have a good test set to tune the weight on. We start with RRF and only move to weighting when the evaluation shows a gain.
Two retrievers run in parallel, so the retrieval stage adds little. The reranker is the cost: it scores each candidate with a model. Keeping the reranked set to 20–50 candidates keeps latency acceptable for interactive search in most set-ups.
Yes. Postgres full-text search provides the keyword side and pgvector the vector side. Both run in one SQL statement and the fusion can be done in SQL or in the application. It is the lowest-effort route when Postgres already holds the content.
When your corpus is prose written in one language, queries are natural-language questions, and nobody searches by code, name or exact phrase. In that case a vector retriever plus a reranker usually matches hybrid on the metrics, with less to operate.
Tell us about your systems, your data and your constraints. We reply within one business day with a straight answer and a suggested next step.