06. Dense Retrieval — Put queries and documents into vector space¶
~15 min read. Dense retrieval stops asking only “same words?” and starts asking “similar meaning?”
Built on the ELI5 in 00-eli5.md. The address label and each letter are now encoded as vectors, not only tokens. Their similarity becomes a new postmark score, then feeds the same delivery route.
1) Core picture: nearby meaning, nearby vectors¶
Look. Imagine every query and every document as a point in space.
Points with similar meaning sit closer together. Points with different meaning sit farther apart.
So instead of checking only sorting bins, we can ask,
“Which letters live nearest to this address label in vector space?” That is dense retrieval.
The vectors are called embeddings. A bi-encoder usually creates them.
One encoder reads the query. Another reads the document.
They are trained together so matched pairs land nearby. ASCII picture.
Simple, no? The geometry replaces pure keyword overlap.2) Bi-encoder retrieval and similarity scores¶
A bi-encoder is fast because query and document are encoded separately. Documents can be encoded once and stored.
At query time, you only encode the address label.
Then compare it with stored document vectors. Two common similarity choices are dot product and cosine similarity.
Dot product uses magnitude and direction together. Cosine similarity mostly cares about angle.
Cosine formula is:
cos(q, d) = (q·d) / (||q|| × ||d||) Picture before formula.
Vectors pointing in the same direction get high cosine. Vectors at right angles get zero.
Vectors pointing opposite get negative values. That is the mental model.
3) Worked numerical example: cosine by hand¶
Let the query vector be:
q = (1, 2, 0)
Three document vectors are:
d1 = (1, 1, 0) d2 = (2, 0, 1)
d3 = (0, 2, 1) Step 1: compute dot products.
q·d1 = 1×1 + 2×1 + 0×0 = 3 q·d2 = 1×2 + 2×0 + 0×1 = 2
q·d3 = 1×0 + 2×2 + 0×1 = 4 Step 2: compute norms.
||q|| = sqrt(1^2 + 2^2 + 0^2) = sqrt(5) ≈ 2.236 ||d1|| = sqrt(1^2 + 1^2 + 0^2) =
sqrt(2) ≈ 1.414
||d2|| = sqrt(2^2 + 0^2 + 1^2) = sqrt(5) ≈ 2.236 ||d3|| = sqrt(0^2 + 2^2 + 1^2) =
sqrt(5) ≈ 2.236
Step 3: compute cosine scores. cos(q,d1) = 3 / (2.236 × 1.414) ≈ 3 / 3.162 ≈ 0.949
cos(q,d2) = 2 / (2.236 × 2.236) = 2 / 5 = 0.400 cos(q,d3) = 4 / (2.236 × 2.236) =
4 / 5 = 0.800
Final ranking by cosine postmark score:
D1 = 0.949 D3 = 0.800
D2 = 0.400 See the point.
Even without exact token overlap, the model can learn that semantically similar texts should live nearby.
4) Training and ANN search¶
How do the vectors learn that structure? Usually with contrastive learning.
Positive query-document pairs are pulled together. Negative pairs are pushed apart.
So the geometry becomes useful for retrieval. But there is a practical issue.
Comparing one query vector with every stored letter vector is expensive. At scale, we use ANN,
Approximate Nearest Neighbor search.
Common tools and ideas include:
-
HNSW graphs
-
FAISS indexes
-
IVF and product quantization ANN gives speed by accepting small approximation error. That trade-off is usually worth it.
Fast search matters.
5) What dense retrieval fixes, and what it misses¶
Dense retrieval helps with semantic similarity. heart attack can match myocardial
infarction.
car repair can match automobile maintenance. That is powerful.
But it has blind spots too. Rare proper nouns can be fragile.
Exact IDs can be fragile. A query like invoice INV-20240315 wants exact token
fidelity.
Dense models may blur that. They are also heavier than pure inverted-index lookup.
So the old sorting bins do not disappear. They stay useful.
Yes? Dense retrieval expands capability,
not total replacement.
6) Retrieval versus reranking¶
Bi-encoders are good for first-pass retrieval because they are fast. Encode query once.
Search nearest document vectors. That is manageable.
But because query and document are encoded separately, the interaction is shallower than a cross-encoder.
So dense retrieval is usually stage one. A later express lane reranker may inspect the shortlist more carefully.
Keep that pipeline in mind.
6) Why not BM25 plus synonyms only under this workload¶
The tempting alternative is BM25 plus synonyms only. It keeps the system simple, and on a toy corpus it often looks good enough.
It breaks when meaning can match even when words do not overlap, but embeddings hide exact lexical constraints. At that point the search system needs an inspectable artifact: query vector, document vector, similarity score, and nearest-neighbour list. Without that artifact, the team argues about ranking quality from anecdotes instead of traces.
| Option | Works when | Fails when | Cost moves to |
|---|---|---|---|
| BM25 plus synonyms only | corpus is small or intent is obvious | meaning can match even when words do not overlap, but embeddings hide exact lexical constraints | user trust and manual debugging |
| dense retrieval | the failure can be measured before serving | traces or judgments are missing | indexing, scoring, evals, and review |
Mini-FAQ. "Is this overkill for a simple app?" Maybe. The mechanism earns its place when query failures are frequent, expensive, or hard to diagnose from the final result list alone.
7) Production signals — know whether dense retrieval is working¶
Healthy behavior: query vector, document vector, similarity score, and nearest-neighbour list explains why the top results changed.
First metric to watch: semantic-rescue rate.
Misleading metric: average click-through rate. Clicks are position-biased, presentation-biased, and often do not prove satisfaction.
Expert graph: break quality down by query class, source type, language, freshness, and result position. Search failures hide in slices long before the global dashboard moves.
bad search result
-> query trace
-> candidate generation
-> scoring / ranking artifact
-> judged list or user feedback
-> targeted tuning change
8) Boundary — where dense retrieval helps and where it does not¶
Strong fit: the failure is visible in candidate generation, scoring, ranking, or judged result lists.
Weak fit: the corpus does not contain the answer, the user's intent is unknowable, or the business objective is unresolved.
Pathology: the team keeps tuning scores when the real issue is missing content, stale content, or unclear product policy.
Scale limit: every extra retrieval branch, feature, or reranker spends latency and operator attention. Put expensive steps on the queries where the quality gain is measurable.
9) Wrong model — vectors understand every user intent automatically¶
The wrong model sounds plausible because it works on simple examples.
Production search is harsher. Users bring short queries, typos, rare entities, ambiguous intent, changing corpora, and biased feedback. The ranking stack has to expose those pressures instead of hiding them behind one score.
If dense retrieval cannot change candidate generation, ranking, evaluation, or debugging, it is not carrying its weight.
10) Failure taxonomy for dense retrieval¶
- Candidate failure — the right document never enters the candidate set.
- Scoring failure — the right document is present but ranked too low.
- Intent failure — the system optimizes for the wrong interpretation of the query.
- Calibration failure — scores from different sources are compared as if they mean the same thing.
- Feedback failure — clicks or labels reflect position, popularity, or annotator disagreement rather than true relevance.
- Freshness failure — stale documents outrank newer but necessary content.
- Debugging failure — no trace connects query, candidates, scores, and final route.
11) Pattern transfer — where this returns later¶
- RAG uses the same candidate-generation and ranking chain before answer synthesis.
- Vector databases make the latency and recall tradeoff physical.
- Advanced RAG reuses query understanding, hybrid fusion, and reranking under stricter evidence constraints.
- Evals in production reuse judged lists, slice analysis, and false-positive/false-negative review.
12) Design review checklist¶
- What failure does this mechanism catch: candidate, scoring, intent, calibration, feedback, or freshness?
- What artifact would you inspect first: query parse, postings list, vector neighbors, feature row, rerank score, or judged list?
- Why is BM25 plus synonyms only weaker for this workload?
- Which query slice should improve first?
- Which latency, memory, or labeling cost rises first?
- What rollback signal tells you the tuning made search worse?
Where this lives in the wild¶
-
Semantic search at Notion — retrieval engineers use embeddings to surface related notes beyond exact wording.
-
RAG pipelines in Pinecone-backed apps — ML engineers retrieve semantically similar chunks from vector indexes.
-
Weaviate-powered enterprise search — platform teams match policy questions to answer passages.
-
Customer support retrieval at Intercom — search engineers use dense vectors to catch paraphrased issues.
-
Semantic Scholar search — IR teams map question-like queries to semantically aligned papers and abstracts.
-
Enterprise search — mixes exact product names, acronyms, policies, and natural-language questions.
- Ecommerce search — balances lexical match, popularity, personalization, freshness, and business rules.
- Support knowledge bases — need high recall for policy questions and high precision for top answers.
- Code search — exact identifiers and semantic intent both matter.
- Legal search — missing one relevant document can be worse than showing extra documents.
- Medical literature search — query expansion helps, but false positives are expensive.
- RAG retrievers — use IR as the evidence gateway before generation.
- Recommendation feeds — reuse ranking ideas even when the item source is not text.
- Ad search — relevance competes with auction and business constraints.
- Academic search — citations, freshness, author authority, and topical match all interact.
Recall checkpoint¶
-
What is the central geometric idea behind dense retrieval?
-
Why are bi-encoders fast enough for first-pass search?
-
In the cosine example, why did D1 beat D3?
-
Why do ANN indexes exist in dense retrieval systems?
-
Which artifact would you inspect first for dense retrieval?
- What query slice would you use to prove the improvement is real?
- What is the first cost this mechanism adds?
Interview Q&A¶
Q: Why does dense retrieval help with vocabulary mismatch better than BM25 alone? A: Because it can place semantically related address label and letter texts nearby, even when they share few surface words.
Common wrong answer to avoid: "Dense retrieval just stores more synonyms in memory.".
Q: Why use cosine similarity instead of raw dot product sometimes? A: Because cosine normalizes vector magnitude and focuses on direction. That often makes similarity comparison more stable across embeddings.
Common wrong answer to avoid: "They are always identical, so the choice never matters.".
Q: Why can dense retrieval fail on invoice numbers or rare product IDs? A: Because semantic compression can blur exact symbolic strings. Sparse methods preserve exact token identity much better.
Common wrong answer to avoid: "Semantic retrieval is strictly better for every query type.".
Q: Why do we need ANN rather than exact nearest-neighbor search at scale? A: Because comparing against every stored vector is too slow and costly. ANN gives strong recall-speed trade-offs for large corpora.
Common wrong answer to avoid: "ANN exists only because training embeddings is slow.".
Q: What artifact would you inspect first when dense retrieval fails? A: I would inspect query vector, document vector, similarity score, and nearest-neighbour list, then walk backward to query parsing, candidate generation, and score construction.
Common wrong answer to avoid: "Just look at the final top result." — The final result hides whether the failure happened in candidate generation, scoring, or evaluation.
Q: How do you know the change helped rather than just moved scores around? A: Track semantic-rescue rate on a judged query slice and compare it with latency, zero-result rate, and false-positive review.
Common wrong answer to avoid: "The average score went up." — Search scores are not comparable across all rankers, branches, or query types unless calibrated.
Q: When should you avoid this mechanism? A: Avoid it when the corpus is tiny, the query class is low-risk, or the team lacks labels and traces to evaluate the change.
Common wrong answer to avoid: "More ranking sophistication is always better." — Sophistication without evaluation adds latency and hides failure modes.
Apply now (10 min)¶
Exercise. Take one query and three short passages.
Pretend each is mapped to a 2D or 3D point. Now rank them by geometric closeness.
Sketch.
query Q
├─ nearest point ──→ strongest candidate letter
├─ next point ──→ second candidate
└─ far point ──→ likely irrelevant
- Reproduce from memory: explain dense retrieval with its pressure, artifact, metric, boundary, and failure mode.
What you should remember¶
Dense retrieval exists because meaning can match even when words do not overlap, but embeddings hide exact lexical constraints. The practical question is not whether the score sounds elegant; it is whether the system can show why a document entered the candidate set, why it received its score, and why it appeared at its final position.
The artifact to inspect is query vector, document vector, similarity score, and nearest-neighbour list. If you cannot inspect it, you cannot reliably debug relevance.
Remember:
- Search quality fails in candidate generation, scoring, intent understanding, calibration, feedback, and freshness.
- Watch semantic-rescue rate by query slice before trusting global averages.
- A good ranking system is explainable enough for operators, not just accurate enough on a benchmark.
- Every retrieval upgrade should name the quality gain and the latency, memory, or labeling cost it adds.
Bridge. sparse sorting bins and dense vectors each shine on different problems, so next we compare where each one wins or loses. → 07-sparse-vs-dense.md