What Is Cosine Similarity? β Definition and How It Works
Learn what cosine similarity measures, why it ignores magnitude, how normalisation turns it into a dot product, and its limits.
Cosine similarity measures the angle between two vectors, ignoring their length. It is the standard similarity metric for text embeddings.
1. The Definition
cos(A, B) = (A Β· B) / (βAβ βBβ)
The dot product divided by the product of the magnitudes. The result runs from -1 to 1:
| Value | Meaning |
|---|---|
| 1 | Same direction β maximally similar |
| 0 | Orthogonal β unrelated |
| -1 | Opposite direction |
In practice, modern text embeddings rarely produce negative similarities, so the useful range is roughly 0 to 1.
2. Why Ignoring Magnitude Is the Point
Two documents about the same topic, one three paragraphs and one thirty, produce embeddings pointing in a similar direction with different magnitudes.
Euclidean distance would call them far apart because of the length difference. Cosine similarity calls them similar because it only asks which way the vectors point.
For text that is almost always what you want β topic, not volume.
3. Normalise Once, Then It's Just a Dot Product
If every vector is normalised to unit length, the denominator becomes 1 and cosine similarity reduces to the dot product:
import numpy as np
def normalize(m):
return m / np.linalg.norm(m, axis=1, keepdims=True)
docs = normalize(np.asarray(doc_vectors, dtype=np.float32))
q = normalize(np.asarray([query_vector], dtype=np.float32))[0]
scores = docs @ q # cosine similarity, one matrix multiply
top = np.argsort(-scores)[:10]
Normalising at index time rather than at query time is the standard optimisation: it turns every subsequent comparison into a plain dot product, which is why vector databases store normalised vectors and offer "inner product" as a metric.
4. Cosine, Dot Product, Euclidean
| Metric | Sensitive to magnitude | Typical use |
|---|---|---|
| Cosine | No | Text embeddings |
| Dot product | Yes | Normalised vectors, or where magnitude is meaningful |
| Euclidean (L2) | Yes | Spatial data, some image embeddings |
On normalised vectors all three rank identically, which is why the choice often does not matter β as long as the vectors really are normalised. Mixing normalised and unnormalised vectors in one index silently corrupts ranking.
5. What the Number Does Not Mean
It is not a probability. 0.85 does not mean 85% likely relevant.
It is not comparable across models. One embedding model's 0.7 may be another's 0.9 for the same pair. Thresholds must be calibrated per model.
It is not comparable across query types. Short queries tend to produce lower similarities than long ones against the same corpus.
High similarity is not relevance. Two chunks of boilerplate are highly similar to each other and useless to the user.
That last point is why a similarity threshold is a weak relevance filter, and why reranking exists.
6. The Practical Traps
- Unnormalised vectors in an index that assumes normalisation β ranking silently degrades.
- A hard threshold ported between models or corpora.
float32vsfloat64mismatches in comparison code.- Near-duplicate documents dominating results, since they are similar to everything the original was.
- Very short chunks producing unstable directions, so similarity is noisy.
7. Using It Well
- Normalise at index time; treat the metric as a dot product thereafter.
- Calibrate any threshold on your own data, with your own model.
- Deduplicate results β near-identical chunks otherwise fill the top ranks.
- Rerank the top candidates with a stronger model rather than trusting similarity alone.
- Combine with a lexical score, since cosine alone misses exact identifiers.
8. Summary
Cosine similarity is the angle between two vectors, ignoring magnitude, which suits text because it compares topic rather than length.
Normalise vectors at index time so the metric becomes a plain dot product, and remember the score is not a probability and not portable between models β so calibrate thresholds on your own data, deduplicate near-identical results, and rerank rather than treating similarity as relevance.