Why does vector search miss exact matches?
An embedding is a summary of meaning, and rare tokens carry almost none of it. Search for SKU A17-B and the embedding dissolves it into a rough neighborhood of product-code-ish text, so the exact match is gone before scoring even starts.
A keyword index does the opposite: BM25 scoring on term frequency, term rarity, and document length (Robertson & Zaragoza, 2009) matches those tokens exactly, which is why keyword search still anchors most production systems.
Why does keyword search miss paraphrases?
To a keyword index, "car" and "automobile" are unrelated strings. Any query phrased differently from the document scores zero, no matter how close the meaning. Your user asked a perfectly good question, phrased it differently from the document, and got nothing. Embeddings exist precisely to close that gap.
Vector only
Query: SKU A17-B
Blurred into a semantic neighborhood
Exact token lost
Misses identifiers
Keyword only
Query: automobile
No token overlap with car
Paraphrase scores zero
Misses meaning
How do the two get combined?
This is the real design decision, and you have three options: merge two ranked lists by position (RRF), normalize and weight the raw scores (score fusion), or score every signal inside one query (true hybrid). Each one trades tuning effort for control over the final ranking. We compare all three in RRF vs score fusion vs true hybrid.
How do you know you actually need it?
Look at your failed queries. If they cluster around exact identifiers, you're missing keyword search; if they cluster around rephrasings, you're missing vectors. When you see both patterns, you need hybrid, and most real query streams get there fast.
TopK runs keyword, vector, and multi-vector scoring in a single query with one ranking expression, so you never stitch together a second engine or a fusion layer. In TopK's BEIR case study (July 2025), that single-query approach scored 4.58% higher nDCG@10 on average than fusing two result lists with RRF. The whole thing is one query:
from topk_sdk.query import select, field, fn, matchdocs = client.collection("articles").query(select("title",semantic=fn.semantic_similarity("content", "climate change policies"),keyword=fn.bm25_score(),).filter(match("carbon") | match("renewable energy")).sort(field("semantic") * 0.6 + field("keyword") * 0.4, asc=False).limit(10))
The true hybrid search guide covers the full API.