A team indexed embeddings under cosine but queried with Euclidean, and recall collapsed. Diagnose the cause.
A production team built their HNSW index with the distance metric set to cosine, then later switched the query-side metric to Euclidean to 'test something.' Recall@10 dropped from 0.95 to near random. Explain in concrete terms why this happened and what fix is required.
HNSW edges were chosen under cosine. Searching them with Euclidean follows edges that point in the wrong direction for the new metric, so the greedy walk strands in the wrong region.
Imagine someone built a subway map where the lines connect stations that are close in **walking distance**. Now you decide to use that same map but you want to travel by **car**. The lines on the map no longer reflect car distances; following them, you end up far from your destination. The map (the index graph) is welded to the distance it was built for. To use a different distance, you need a different map.
Detailed answer & concept explanation~3 min readEverything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example.
Everything important, quickly.
3 min: graph edges encode the metric explanation + cosine versus dot exception with the unit-vector identity + rebuild as the only correct fix + operational guardrails (Qdrant/pgvector declare at creation).
| Metric swap | Safe? | When |
|---|---|---|
| Cosine -> Dot product | Yes | Only on L2-normalized vectors |
| Cosine -> Euclidean | No | Different orderings on unnormalized vectors |
| Dot product -> Euclidean | No | Different orderings |
| Cosine -> Cosine (different index) | Yes (trivially) | Same metric, same ordering |
Real products, models, and research that use this idea.
- Qdrant requires the distance metric to be declared at collection creation and refuses to swap it on existing collections.
- pgvector also requires the metric to be picked at index creation (`USING ivfflat (embedding vector_cosine_ops)` vs `vector_l2_ops`).
- Faiss does not enforce the metric at the API level; teams routinely encounter this bug when migrating between IndexFlatIP and IndexFlatL2.
- Pinecone tracks the metric at index creation and rejects queries that imply a different metric.
What an interviewer would ask next. Try answering before peeking at the approach.
QHow would you migrate metric without downtime?
QWhy does normalization make cosine, dot, and Euclidean coincide?
Don't say thisRed flags and common mistakes that signal junior thinking. Click to expand.
Red flags and common mistakes that signal junior thinking. Click to expand.
Trying to fix the bug by changing the query metric back to cosine while keeping the same index. That works only because the index was correct for cosine to begin with; the real lesson is that the index cannot serve a metric it was not built for.
The night-before-the-interview bullets. Scan these on the way to the call.
Primary sources. Skim if you want the original framing.
Same topic, related formats. Practice these next.