Cosine, Dot Product and Euclidean: Which Similarity to Use
What each metric measures, when normalisation makes them equivalent, and when the choice changes your results.
Similarity metrics decide how a RAG retriever ranks chunk embeddings against a query embedding. Cosine similarity scores the angle between vectors (direction only); the dot product scores angle and magnitude together; Euclidean distance scores the straight-line gap between endpoints. When vectors are unit-length, cosine and the dot product rank identically — and the choice only changes your results when magnitude is still in the numbers. This page covers what each metric measures, when they agree, which to pick for text RAG, and the silent ranking bugs a wrong choice creates. Parent stage: retrieval. The vectors themselves: embeddings.
What is cosine similarity?
Cosine similarity is the cosine of the angle between two embedding vectors — it keeps direction and cancels length. For vectors a and b it is (a · b) / (‖a‖ · ‖b‖), which equals cos θ. The score ranges from −1 (opposite directions) through 0 (orthogonal) to 1 (same direction). That is why cosine is the usual default for text RAG: two passages about the same topic can differ hugely in length, and cosine still treats them as close if they point the same way (Weaviate’s distance-metrics guidance; Miric 2025).
Cosine distance is defined as 1 − cosine similarity, so it ranges from 0 to 2 (Nerd Level Tech 2026; Weaviate). Higher similarity is better; higher distance is worse. Sorting cosine similarity descending and cosine distance ascending are opposite operations — mixing them silently returns your least-similar chunks first.
What is the dot product for embeddings?
The dot product (inner product) of two vectors is a · b = Σ aᵢbᵢ — one sum of element-wise products, with no division by length. It responds to both direction and magnitude: two vectors at the same angle score higher when either is longer. The theoretical range is unbounded.
Use the raw dot product when magnitude is genuine signal — classic recommendation / matrix-factorization setups treat a longer item vector as higher popularity (Qdrant Essentials; Miric 2025). For semantic text embeddings that is usually the wrong bias: without normalisation, longer or higher-norm chunks can outrank shorter, more relevant ones even at the same angle — a silent ranking bug, not an exception (App Lab 2026). When every vector is already unit length, the magnitude term disappears and the dot product is cosine similarity, which is why many engines expose a fast inner-product path after a one-time normalise (OpenAI Embeddings FAQ, as summarised in Nerd Level Tech 2026; Weaviate).
What is Euclidean distance in vector search?
Euclidean distance (L2) is the straight-line gap between two points: ‖a − b‖ = √Σ (aᵢ − bᵢ)². Identical vectors score 0; the distance grows without a fixed upper bound as points move apart. It is sensitive to both direction and magnitude, so a long document embedding and a short one on the same topic can look far apart even when cosine calls them a match (Miric 2025; QualityPoint 2025).
Weaviate exposes squared Euclidean (l2-squared) — the same ordering without the square root, which is cheaper at query time (Weaviate distance-metrics blog). For modern dense text embeddings Euclidean is rarely the first choice; Pinecone’s vector-similarity guidance (cited via Nerd Level Tech 2026) pairs it more often with classical encodings such as locality-sensitive hashing than with deep text models. On unit-length vectors the rankings lock to cosine anyway: squared L2 equals 2 − 2·cos θ, so minimum Euclidean and maximum cosine induce the same order (Nerd Level Tech 2026; App Lab 2026; Qdrant). Reach for L2 when absolute position matters — spatial features, anomaly detection, clustering — or when the embedding model was trained with an L2 / contrastive loss that expects it (Weaviate).
When are cosine and dot product the same?
Cosine similarity and the bare dot product are identical when both vectors are L2-normalised to length 1: the denominator in the cosine formula becomes 1, so cosine reduces to a · b. On those unit vectors, Euclidean ranking agrees too. The disagreement appears only while magnitude is still in the numbers. The arithmetic below is structural (the formulas applied to fixed vectors), not a published benchmark:
| Vector | Components | Cosine similarity | Dot product | Euclidean distance |
|---|---|---|---|---|
| query | [1, 0, 1] | — | — | — |
| docA (same direction, same length) | [1, 0, 1] | 1.000 | 2.000 | 0.000 |
| docB (orthogonal) | [0, 1, 0] | 0.000 | 0.000 | 1.732 |
| docC (same direction, 2× length) | [2, 0, 2] | 1.000 | 4.000 | 1.414 |
Cosine calls docA and docC a perfect directional match. The raw dot product ranks docC above docA because it is longer. Euclidean prefers docA (distance 0) over docC (≈1.414) over docB (≈1.732). After normalize(query) and normalize(docC), both become [≈0.707, 0, ≈0.707] and the dot product equals cosine at 1 (Nerd Level Tech 2026 worked demo).
Production implication: normalise once at write time (and normalise the query the same way), then search with inner product for speed — or configure cosine and let the engine handle length. Qdrant’s Cosine collections automatically normalise vectors so Cosine, Dot, and Euclidean give the same ranking for a fixed query once vectors are unit length (Qdrant Essentials). Never mix normalised and unnormalised vectors in the same index (App Lab 2026).
Which similarity metric should you use for RAG?
The decision rule shared across Weaviate, Qdrant, and Pinecone’s vector-similarity guidance is: match the metric your embedding model was trained with. Read the model card. If the docs are unclear, cosine is the safe default for text RAG (Qdrant Essentials; QualityPoint 2025).
- Unit-normalised text models — OpenAI’s Embeddings FAQ states that its embeddings (including text-embedding-3-small and text-embedding-3-large) are normalised to length 1, so cosine, dot product, and Euclidean produce identical rankings; OpenAI recommends computing cosine via a plain dot product for speed (as of the FAQ cited in Nerd Level Tech, June 2026 — verify before you rely on it). Miric (2025) similarly lists OpenAI, Cohere, Voyage, and Nomic as typically unit-length; confirm on the current model card.
- Non-normalised models trained for dot product — Sentence-Transformers’ msmarco-bert-base-dot-v5 is documented as non-normalised and intended for dot-product comparison (sbert.net MSMARCO docs via Nerd Level Tech 2026). Using cosine on that model erases magnitude the training objective kept.
- Euclidean / L2 — spatial data, anomaly detection, clustering, or an L2-trained encoder. Not the default for variable-length text chunks (QualityPoint 2025; Miric 2025).
- Recommendation-style magnitude — if popularity or activity is encoded in vector length, keep the raw dot product and do not normalise away the signal (Qdrant; Miric). That is a different job from RAG passage retrieval.
Model defaults move — date-check them
Provider normalisation behaviour and recommended metrics change with model versions. Treat the OpenAI / Cohere / Voyage notes above as as-of mid-2026 secondary citations; the model card in front of you wins. Choosing which embedding model to buy is a separate decision — see embedding model selection.
What happens if you pick the wrong similarity metric?
A mismatched metric does not throw. Scores still look healthy; the ranking is quietly wrong. Four signatures show up in production:
- Unnormalised text + raw dot product — verbose, weakly relevant chunks float above short precise ones because magnitude leaks into the score (App Lab 2026).
- Dot-trained non-normalised model + cosine — the magnitude signal the model learned is discarded, so neighbours scramble relative to the training geometry (Sentence-Transformers MSMARCO dot models via Nerd Level Tech 2026).
- Similarity sorted as distance (or the reverse) — cosine similarity sorted ascending, or cosine distance sorted descending, returns the least-similar chunks first (Nerd Level Tech 2026).
- Mixed normalised and unnormalised vectors in one collection — scores become incomparable across rows (App Lab 2026).
Matching the metric is necessary, not sufficient. Even a correct cosine score can put an irrelevant chunk at top-1 when the embedding space does not capture your domain — that failure is diagnosed on why RAG returns the wrong chunk, not by swapping distance functions again.
How do vector databases configure similarity metrics?
Most vector stores fix the metric when the collection or index is created; changing it usually means a rebuild. The inventory below is configuration fact, not a ranking — Weaviate leads the ordered list as this site’s placement rule requires, with no score claimed:
| Engine | How you set it | Metrics named in docs |
|---|---|---|
| Weaviate | Collection / schema distance | cosine | , dot, l2-squared, hamming, manhattan (Weaviate blog + docs)
| Qdrant | VectorParams.distance | Cosine | , Dot, Euclid, Manhattan (Qdrant Essentials)
| Pinecone | Metric at index create | cosine / dotproduct / euclidean (App Lab checklist citing Pinecone) |
| pgvector | SQL operator per metric | <-> | L2 · <=> cosine distance · <#> negative inner product · <+> L1 (pgvector README v0.8.x via Nerd Level Tech 2026)
| Chroma | hnsw:space metadata | cosine | / ip / l2 (App Lab 2026)
| Azure Cosmos DB | Distance function on vector index | Manhattan, Euclidean, cosine, dot product (Microsoft Learn) |
Manhattan (L1) and Hamming appear in several engines for sparse or binary vectors; they are not the default for dense text RAG and are not expanded here. How the approximate index walks neighbours under that metric is a separate mechanism — see HNSW. Dense similarity is also only half of a hybrid stack; lexical scoring lives on BM25 and hybrid search.
What is the difference between cosine similarity and the dot product?
Cosine similarity is the dot product divided by both vectors' lengths, so it measures only the angle between embeddings (range −1 to 1). The raw dot product keeps magnitude, so longer vectors score higher at the same angle. For unit-length embeddings the two are numerically identical.
Are cosine similarity and the dot product the same after normalisation?
Yes. When both vectors are L2-normalised to length 1, cosine similarity reduces to the bare dot product because the denominator is 1. On those unit vectors, Euclidean distance also induces the same ranking as cosine. The metrics disagree only while magnitude remains in the numbers.
Should you normalise embeddings before storing them?
If you plan to search with raw dot product / inner product, yes — normalise at write time and normalise the query the same way, or magnitude will leak into ranking. If the collection is configured for cosine, the engine typically handles length. Never mix normalised and unnormalised vectors in one index.
When should you use Euclidean distance for RAG?
Use Euclidean (L2) when absolute position matters — spatial features, anomaly detection, clustering — or when the embedding model was trained with an L2 loss. For variable-length text chunks, cosine (or inner product on unit vectors) is the usual default; on already-normalised vectors Euclidean and cosine rank the same anyway.
Which similarity metric should OpenAI embeddings use?
OpenAI’s Embeddings FAQ states that its embeddings are normalised to length 1, so cosine, dot product, and Euclidean produce identical rankings; the FAQ recommends computing cosine via a plain dot product for speed. Confirm on the current model card before you rely on that — defaults are version-sensitive. Broader model choice is covered on the embedding model selection page.