Retrieval
Vector similarity: cosine, dot product and distance
How to compare two embeddings with cosine, dot product or Euclidean distance, and why normalizing vectors makes them agree.
An embedding is a list of numbers, so comparing two texts means comparing two lists. Three formulas cover most product work: cosine similarity, dot product and Euclidean distance. They look different, but with the right setup they rank results the same way.
Concept
A dimension is one coordinate of a vector. A 768-dimensional embedding is a list of 768 numbers. Pictures of 2D or 3D space are only for intuition.
The picture
Think of coordinates on a map. The distance between two points stands in for how far apart two places are. An embedding space works the same way, with hundreds of dimensions instead of two. Billing tickets form one cluster and password tickets form another. A new ticket lands near the cluster that matches its meaning, even when the wording is different.
Three ways to compare
- Cosine similarity compares direction and ignores length. It runs from −1 to 1, and higher means more similar.
- Dot product multiplies matching coordinates and adds the results. It is sensitive to length.
- Euclidean distance is the straight-line gap between two points. Smaller means more similar, which is easy to reverse by mistake.
import math
def cosine(a: list[float], b: list[float]) -> float:
dot = sum(x * y for x, y in zip(a, b))
na = math.sqrt(sum(x * x for x in a))
nb = math.sqrt(sum(y * y for y in b))
return dot / (na * nb)
print(round(cosine([1.0, 2.0], [2.0, 4.0]), 3)) # same direction, different length
print(round(cosine([1.0, 0.0], [0.0, 1.0]), 3)) # perpendicularOutput:
1.0
0.0The first pair scores 1.0 even though one vector is twice as long. Cosine only sees direction.
Why normalizing makes them agree
Scale every vector to length 1. This is called L2 normalization. After that:
- The dot product equals the cosine.
- Euclidean distance satisfies ‖a − b‖² = 2 − 2·cos(a, b), so the nearest point is also the one with the highest cosine.
So normalize once, when you embed, and store unit vectors. Then use the inner product, which is the cheapest operation and the one most search indexes optimize.
Walking through a ranking check
Three documents, A, B and C, have unit vectors. Their dot products with the query are 0.91, 0.77 and 0.40. The ranking is A, B, C.
Now suppose the same directions are stored with lengths 2.0, 0.5 and 1.0. The raw dot products become:
A: 0.91 × 2.0 = 1.82
B: 0.77 × 0.5 = 0.385
C: 0.40 × 1.0 = 0.40The new ranking is A, C, B. Document C moved above B only because B was stored shorter. Retrieval quality looks random after an upgrade that changes normalization.
Scores belong to a model
A cosine of 0.82 means little on its own. Scores from one model do not match scores from another. Use scores to rank results. If you need a "is this a match?" cutoff, measure it on pairs you have labeled yourself.
| Metric | Best when | Watch out for |
|---|---|---|
| Cosine | The default for text embeddings | Costs a little more because of the norm |
| Dot product | Vectors are already unit length | Length changes the ranking if they are not |
| Euclidean | Unit vectors, where it matches cosine | "Smaller is better" is easy to misread |
Common mistakes
- Storing unnormalized vectors in an index that assumes inner product. Rankings drift without any error message.
- Copying a threshold from a blog post written for a different model.
- Comparing scores across models. Each model has its own range.
Check yourself
- Two vectors point the same way, but one is three times longer. What is their cosine? 1.0. Cosine ignores length.
- Why can the ranking change when vectors are not normalized? Dot product includes length, so a longer document can beat a better-aligned one.
Key takeaways
- Cosine compares direction. Dot product and Euclidean distance also depend on length unless the vectors are unit length.
- For unit vectors, all three rank results the same way.
- Normalize at embed time and store unit vectors.
- Calibrate any cutoff on your own labeled pairs.
Further learning
Next, see how the two kinds of embedding models split the work in bi-encoders and cross-encoders.
Related
Embeddings and similarity
Turning text into vectors, measuring similarity, and choosing an embedding model.
Vector search and vector databases
Approximate nearest neighbor algorithms (HNSW, IVF, PQ) and choosing between pgvector and dedicated stores.
Advanced RAG
Hybrid search, reranking, query rewriting, contextual retrieval and measuring retrieval quality.