Cosine similarity measures how closely two vectors point in the same direction. It is the dot product of the two vectors divided by the product of their magnitudes, which works out to the cosine of the angle between them. Two vectors pointing the same way score 1. Two at right angles score 0. Two pointing in opposite directions score -1.
That one number carries most of modern retrieval. Every time an application searches a vector index, pulls context for a RAG prompt, clusters embeddings, or checks whether today’s inputs look like last month’s, something is almost certainly computing cosine similarity underneath. It is worth knowing exactly what it measures, and just as importantly, what it does not.
Build better agents with Arize
Trace, evaluate, and learn. Build agents that work with Arize AX and start tracing your runs today.
Prefer open source? Try Arize Phoenix for self-hosted, open source agent observability.
Key takeaways
- Cosine similarity is
dot(a, b) / (norm(a) * norm(b)), the cosine of the angle between two vectors. It ranges from -1 to 1. - Cosine distance is
1 - cosine_similarity. Smaller distance means more similar. - It ignores magnitude entirely, which is why it is the default for text embeddings: a long document and a short sentence about the same topic can still score high.
- On unit-normalized vectors, cosine similarity, dot product, and Euclidean distance rank results identically. Normalization is why most vector indexes offer inner product as a stand-in.
- A high similarity score means two texts are about similar things. It does not mean the retrieved chunk answers the user’s question, which is why retrieval quality needs its own evaluation.
The cosine similarity formula
For two non-zero vectors a and b of the same dimension:
cosine_similarity(a, b) = dot(a, b) / (norm(a) * norm(b))
= sum(a_i * b_i)
-----------------------------------------
sqrt(sum(a_i^2)) * sqrt(sum(b_i^2))
The numerator is the dot product. The denominator is the product of the two Euclidean norms, or lengths. Dividing by the lengths cancels out magnitude and leaves pure direction.
A small worked example. Let a = [1, 0, 1] and b = [1, 1, 0].
dot(a, b) = (1*1) + (0*1) + (1*0) = 1
norm(a) = sqrt(1 + 0 + 1) = 1.4142
norm(b) = sqrt(1 + 1 + 0) = 1.4142
cosine_similarity = 1 / (1.4142 * 1.4142) = 0.5
A cosine of 0.5 corresponds to a 60 degree angle. Now scale a to [10, 0, 10] and recompute: the answer is still 0.5. That invariance to scale is the whole point.
Cosine distance and the range
Cosine distance is defined as 1 - cosine_similarity. Because similarity spans -1 to 1, the distance spans 0 to 2. In practice, embedding vectors from text models usually have mostly non-negative behavior in aggregate and rarely land in opposite directions, so teams treat similarity as a 0 to 1 scale and distance as 0 to 1 as well. That shortcut is fine for ranking and misleading for thresholds, which is covered below.
Two related quantities get confused with cosine distance. Angular distance is the actual angle, arccos(cosine_similarity), which is a proper metric that satisfies the triangle inequality. Cosine distance does not. If you are feeding distances into an algorithm that assumes metric properties, that difference matters.
Why embedding search defaults to cosine
Text embedding models place semantically related passages near each other in a high-dimensional space. Cosine similarity is the standard comparison for three practical reasons.
Length invariance. A three-sentence answer and a three-page document on the same subject often produce vectors with very different magnitudes. Cosine ignores that. Euclidean distance does not, and would push long passages away from short queries for no useful reason.
Cheap computation on normalized vectors. If you scale every vector to unit length in advance, then norm(a) * norm(b) = 1 and cosine similarity collapses to a plain dot product. Squared Euclidean distance becomes 2 - 2 * cosine_similarity, a strictly decreasing function of similarity, so the ranking is identical. That is why a vector index configured for inner product returns the same order as one configured for cosine, as long as you normalized first.
It matches how the models were trained. Most embedding models are trained with contrastive objectives that operate on normalized vectors, so cosine is the geometry the model was optimized for.
Where cosine similarity misleads
It measures topical direction, not answerhood. This is the failure mode that costs teams the most time. A chunk that discusses refund timelines and a chunk that states the exact refund window both score high against “how long do I have to return this.” Only one answers the question. Similarity ranks by aboutness, and aboutness is not relevance. Retrieval quality is a separate discipline from retrieval, which is the argument behind evaluating RAG with LLM evals and benchmarking.
Scores are not calibrated and thresholds do not transfer. Embedding models tend to squeeze all their outputs into a narrow cone of the space, so unrelated sentences can still score well above 0.5. A cutoff tuned for one model is meaningless on another, and it can quietly break when you upgrade the same model. That is a versioning problem as much as a retrieval problem, and embedding versioning deserves the same care as model versioning. Rank results, do not trust absolute values.
Negation reads as similarity. “The policy allows international returns” and “the policy does not allow international returns” share nearly all of their content words and land close together. Cosine has no mechanism to notice the flip.
Chunking often dominates the metric. If the passage boundaries split a fact from its qualifier, no similarity function can recover it. Comparing chunking strategies for RAG retrieval usually moves recall more than swapping distance functions does. One documented retrieval repair, raising RAG recall from 39% to 75%, came from fixing the pipeline around the scores rather than the scoring itself.
Cosine distance for drift and monitoring
The same formula does a second job in production. Take the centroid of a reference window of embeddings, take the centroid of a current window, and compute the cosine distance between them. A rising distance means the inputs your model sees have moved away from the inputs it was validated on. The mechanics, including the sampling and windowing decisions that make or break the signal, are laid out in measuring embedding drift. The caveat is the same as always: a centroid is a summary, and two very different distributions can share one.
FAQ
What is the formula for cosine similarity?
cosine_similarity(a, b) = dot(a, b) / (norm(a) * norm(b)). Written out, that is the sum of elementwise products divided by the product of the square roots of the sums of squares. Both vectors must be non-zero, since a zero vector has no direction and the denominator would be zero.
What is cosine distance?
Cosine distance is 1 - cosine_similarity. It ranges from 0 to 2, where 0 means the vectors point the same way. Vector databases usually report distance rather than similarity so that smaller is better and results sort ascending.
What is the range of cosine similarity?
Mathematically, -1 to 1. For text embeddings you will almost always see positive values, so the effective range is closer to 0 to 1. Do not read that as calibration: the absolute number depends on the model, and only the relative order is dependable.
Is cosine similarity the same as the dot product?
Only when both vectors are unit length. Otherwise the dot product mixes direction and magnitude, while cosine similarity isolates direction. Normalizing first is the standard trick, and it is why inner product search and cosine search return the same ranking on normalized data.
When should I use Euclidean distance instead?
When magnitude carries meaning. Count vectors, raw feature values, coordinates, and anything where “how much” matters as well as “which way” are better served by Euclidean distance. For semantic text retrieval, magnitude is mostly noise from passage length, so cosine is the safer default. Either way, judge the choice by measured retrieval quality rather than by which metric sounds more principled.