Overview
The argument in four moves.
1. From Words to Geometry
Why lexical matching cannot answer the question search actually asks.
Keyword retrieval scores documents on lexical overlap. It is fast, interpretable, and blind in a specific way: "How do I reset my password?" and "Steps to recover account access" share almost no terms and nearly all of their meaning. Term-based scoring has no mechanism to see that, because its only evidence is which strings coincide.
Semantic search replaces string identity with a representation. Each piece of text is mapped to a point in a continuous space, chosen so that texts meaning similar things land in similar places. Comparison then becomes arithmetic on coordinates rather than matching on tokens, and the question "do these mean the same thing?" is answered by a proxy: "are these two vectors aligned?"
That substitution is the whole subject of this paper. It proceeds in one chain:
flowchart LR L["Language
query, document"] --> M["Embedding model
trained encoder"] M --> V["Vector representation
fixed dimension d"] V --> G["Semantic relations become
geometric relations"] G --> C["Cosine similarity
directional alignment"] C --> S["Relevance score"] S --> R["Ranking"] R --> I["Vector index
scalable retrieval"] style M fill:#e8f1ff,stroke:#3975c6 style C fill:#e8f7f1,stroke:#157a5a,stroke-width:2px style G fill:#fff7e6,stroke:#9a6500
2. What an Embedding Actually Represents
Cosine is a function of nothing but the two vectors handed to it. Whatever geometry it reports was inherited entirely from whatever produced them.
2.1 Four things that are not the same
The word "embedding" is used for at least four distinct objects. Conflating them is the single most common source of confusion about why cosine sometimes works and sometimes does not.
| Object | What it is | Changes per input? |
|---|---|---|
| Parameters (weights) | Numbers learned during training and frozen at inference. Includes the input embedding matrix — one static vector per vocabulary token. | No |
| Activations | Values computed inside the network while processing one input. | Yes |
| Hidden states | The per-token activations at a given layer. For an \(n\)-token input: \(n\) vectors, not one. | Yes |
| Pooled representation / embedding | The \(n\) hidden states reduced to a single \(d\)-dimensional vector by a pooling rule. This is what gets stored and compared. | Yes |
Only the last is what a vector database holds. It is an activation, not a parameter: it exists only because a specific text was passed through the model.
2.2 The pipeline
flowchart TB T["Raw text"] --> TK["Tokenizer
subword units"] TK --> LU["Static token vectors
lookup — context-free"] LU --> EN["Transformer layers
attention + feed-forward"] EN --> HS["Hidden states
one vector per token"] HS --> PO["Pooling
mean / CLS / last-token"] PO --> NM["L2 normalization
optional but common"] NM --> EM["Stored embedding
d numbers"] style EN fill:#e8f1ff,stroke:#3975c6 style PO fill:#fff7e6,stroke:#9a6500 style EM fill:#e8f7f1,stroke:#157a5a,stroke-width:2px
2.3 Contextualization is what makes the geometry possible
The lookup step assigns one vector per token regardless of context, so bank in "river bank" and "savings bank" begin identically. The transformer layers fix this: each token's representation is recomputed as a function of the other tokens it is permitted to attend to. By the upper layers, the two bank tokens have been pulled apart.
2.4 Pooling, and why the choice is not cosmetic
Pooling must turn \(n\) vectors into one. Mean pooling averages all token states; CLS pooling reads a designated position; last-token pooling reads the final position — the natural choice for a causal model, since it is the only position that has seen the whole input.
Each rule discards different information, and none is universally correct. What matters is consistency with training: a model fine-tuned with mean pooling in the loss will produce a usable space under mean pooling and a degraded one under CLS pooling. The pooling rule is part of the model's contract, not a post-hoc convenience.
2.5 The misconception that costs the most
2.6 In one sentence
An embedding is a pooled activation of a trained encoder, of a dimension fixed in advance, whose usefulness for angular comparison is a consequence of the objective that shaped it.
3. The Geometry of a Vector
Magnitude, direction, inner product, norm, angle — the five quantities the rest of the paper needs.
3.1 Two independent pieces of information
A vector \(a=(a_1,\dots,a_d)\) carries exactly two separable things: how long it is and which way it points. Formally, \(a = \lVert a\rVert \cdot \hat a\), where
$$\lVert a\rVert=\sqrt{\sum_{i=1}^{d} a_i^2}, \qquad \hat a=\frac{a}{\lVert a\rVert},\quad \lVert \hat a\rVert = 1 .$$The decomposition is unique for any \(a\neq 0\). Every similarity function is, in effect, a choice about how much weight to give each part.
3.2 The inner product, and what it already knows about angle
The dot product is a sum of coordinate-wise products:
$$a\cdot b=\sum_{i=1}^{d} a_i b_i .$$It is large when the two vectors agree in sign and magnitude coordinate by coordinate, and negative when they systematically disagree. It also carries angular information already — but entangled with length, since scaling \(a\) by \(5\) scales \(a\cdot b\) by \(5\) without rotating anything. Disentangling the two is precisely what cosine does.
3.3 Euclidean distance is magnitude-sensitive
Take \(A=(2,3,5)\) and \(B=(4,6,10)=2A\). These point in exactly the same direction — the angle between them is \(0\). Yet
$$\lVert A-B\rVert=\lVert A-2A\rVert=\lVert -A\rVert = \sqrt{2^2+3^2+5^2}=\sqrt{38}\approx 6.164 .$$Raw Euclidean distance calls them far apart purely because one is twice as long. If the application treats \(A\) and \(2A\) as meaning the same thing, this is the wrong comparison.
4. Cosine Similarity: The Central Mechanism
The core of the paper. What the quantity is, why it is bounded, and exactly what normalization keeps and discards.
4.1 The definition, and where it comes from
For nonzero \(a,b\in\mathbb{R}^d\),
$$\cos\theta = \frac{a\cdot b}{\lVert a\rVert\,\lVert b\rVert}.$$This is not a definition invented for search; it is forced by the law of cosines. For the triangle with sides \(a\), \(b\) and \(a-b\):
Expanding the left side through the inner product:
$$\lVert a-b\rVert^2=(a-b)\cdot(a-b)=\lVert a\rVert^{2}-2(a\cdot b)+\lVert b\rVert^{2}$$Equating and cancelling \(\lVert a\rVert^2+\lVert b\rVert^2\) from both sides:
$$-2(a\cdot b)=-2\lVert a\rVert\lVert b\rVert\cos\theta \quad\Longrightarrow\quad \cos\theta=\frac{a\cdot b}{\lVert a\rVert\lVert b\rVert}$$So the division by two lengths is not a normalization applied to the dot product as an afterthought. It is what the dot product was always missing in order to be an angle. Assumption: \(a\neq 0\) and \(b\neq 0\). The zero vector has no direction and cosine is undefined for it — an edge case worth handling explicitly in code, since a zero-length embedding silently produces \(0/0\).
4.2 Why the value is bounded in \([-1,+1]\)
The bound is not empirical. It is the Cauchy–Schwarz inequality, which states that for any \(a,b\in\mathbb{R}^d\),
$$|a\cdot b| \le \lVert a\rVert\,\lVert b\rVert .$$Proof sketch. For any \(t\in\mathbb{R}\), \(\lVert a-tb\rVert^2 \ge 0\) because it is a sum of squares. Expanding gives the quadratic in \(t\):
$$\lVert a\rVert^{2}-2t(a\cdot b)+t^{2}\lVert b\rVert^{2}\;\ge\;0 .$$A quadratic that is never negative has a non-positive discriminant, so \(4(a\cdot b)^2-4\lVert a\rVert^2\lVert b\rVert^2\le 0\), which rearranges to \((a\cdot b)^2\le\lVert a\rVert^2\lVert b\rVert^2\). Taking square roots gives the inequality; dividing through by \(\lVert a\rVert\lVert b\rVert>0\) gives \(|\cos\theta|\le 1\). Equality holds exactly when \(a\) and \(b\) are linearly dependent — that is, parallel or antiparallel.
This gives the three landmark values a precise geometric reading:
| \(\cos\theta\) | \(\theta\) | Geometric meaning | Retrieval reading |
|---|---|---|---|
| \(+1\) | \(0^\circ\) | Same direction; \(b=\lambda a\) for some \(\lambda>0\) | Maximal alignment |
| \(0\) | \(90^\circ\) | Orthogonal; \(a\cdot b=0\) | No directional relationship |
| \(-1\) | \(180^\circ\) | Opposite direction; \(b=\lambda a\), \(\lambda<0\) | Maximal anti-alignment |
4.3 The interactive figure: drag the vectors
Everything above is two-dimensional and visible. Drag either arrowhead. Watch which readouts change and which refuse to. The green dashed arrow is the projection of \(a\) onto \(b\) — the geometric object the dot product actually measures.
Answer. Exactly \(1.000\). \(b=2a\), so the vectors are linearly dependent and Cauchy–Schwarz holds with equality. Length difference is invisible to cosine by construction — this is the scale invariance that makes the metric useful when text length should not drive similarity.
4.4 Normalization: the same comparison, pre-paid
If every vector is scaled to unit length before storage, then \(\lVert \hat a\rVert=\lVert \hat b\rVert=1\) and
$$\hat a\cdot\hat b=\frac{a\cdot b}{\lVert a\rVert\lVert b\rVert}=\cos\theta .$$Cosine similarity on raw vectors is identical to the inner product on normalized vectors. The division has not vanished; it has been paid once at indexing time instead of once per comparison at query time. This identity is the reason §7 works at all.
flowchart LR
subgraph RAW["Raw space — length varies freely"]
A1["a = (4,1)
‖a‖ = 4.12"]
B1["b = (−1,3)
‖b‖ = 3.16"]
end
RAW -->|"divide each by its norm"| SPH
subgraph SPH["Unit sphere — only direction survives"]
A2["â
‖â‖ = 1"]
B2["b̂
‖b̂‖ = 1"]
end
SPH --> DP["Inner product â · b̂
= cos θ, no division"]
style SPH fill:#e8f7f1,stroke:#157a5a
style DP fill:#fff7e6,stroke:#9a6500,stroke-width:2px
4.5 Ranking by cosine and by Euclidean distance are the same ranking
On normalized vectors, expand the squared distance:
So \(\lVert \hat a-\hat b\rVert=\sqrt{2-2\cos\theta}\), a strictly decreasing function of \(\cos\theta\) on \([-1,1]\). Sorting ascending by Euclidean distance and sorting descending by cosine therefore produce identical orderings — not similar ones, identical.
4.6 Cosine distance is not a metric
It is tempting to treat \(1-\cos\theta\) as a distance. It is non-negative and zero exactly when vectors are parallel, but it violates the triangle inequality. Take \(x=(1,0)\), \(y=(\tfrac{1}{\sqrt2},\tfrac{1}{\sqrt2})\), \(z=(0,1)\):
$$1-\cos(x,z)=1,\qquad \big(1-\cos(x,y)\big)+\big(1-\cos(y,z)\big)=2\left(1-\tfrac{1}{\sqrt2}\right)\approx 0.586 .$$Since \(1 > 0.586\), the inequality fails. The angular distance \(\theta/\pi\) is a true metric (here \(0.5 \le 0.25+0.25\), holding with equality), and some systems use it for that reason. This matters when an algorithm's correctness depends on metric axioms; for pure top-\(k\) ranking it does not, since ranking needs only monotonicity.
5. Why Cosine Can Represent Semantic Similarity
The conceptual bridge. Nothing in §4 mentioned meaning — and nothing in §4 could have.
5.1 The question stated honestly
Section 4 established what \(\cos\theta\) is: a bounded, scale-invariant measure of directional alignment, derived from the law of cosines. Every result there holds for arbitrary vectors — stock prices, pixel intensities, random noise. None of it mentions language, and none of it could, because cosine similarity is a function of two arrays of numbers and nothing else.
So why should the angle between two embedding vectors have anything to do with meaning?
Cosine similarity does not understand semantics. It is a fixed arithmetic operation with no knowledge of anything.
The embedding model creates a representation space in which semantic relationships are encoded as geometric ones.
Cosine similarity then measures directional alignment within that learned space.
The semantics live in the space. The geometry lives in the metric. Neither does the other's job, and attributing understanding to the metric is the error that makes the rest of the subject confusing.
5.2 What the training objective actually arranges
A representation space in which angle tracks meaning does not arise by accident. It arises because an objective function penalised the alternative. The widely used family is contrastive: given an anchor text \(q\), a semantically related positive \(p\), and negatives \(n_i\), the loss rewards high similarity for \((q,p)\) and low similarity for \((q,n_i)\). In the common InfoNCE form, with similarity function \(s\) and temperature \(\tau\):
$$\mathcal{L} = -\log\frac{\exp\!\big(s(q,p)/\tau\big)}{\exp\!\big(s(q,p)/\tau\big)+\sum_i \exp\!\big(s(q,n_i)/\tau\big)}$$The decisive detail is that \(s\) is typically cosine similarity itself. Gradient descent is therefore directly rewarded for arranging directions so that cosine reads high on related pairs and low on unrelated ones. The geometry is not a byproduct of training — it is the thing trained.
5.3 When cosine is not meaningful: the scaling degrees of freedom
There is a precise and important failure case, and it is the strongest argument for §5.2's rule. Steck, Ekanadham and Kallus (2024) analyse linear matrix-factorization models and show the following. Suppose embedding matrices \(A\) and \(B\) are learned such that reconstruction depends only on the product \(AB^\top\). Then for any invertible diagonal matrix \(D\), the pair \((AD,\,BD^{-1})\) is an equally optimal solution, because
$$(AD)(BD^{-1})^{\top} = A D D^{-1} B^{\top} = AB^{\top}.$$The inner product is invariant under this transformation. Cosine similarity is not: \(D\) rescales individual coordinates, which changes both norms and the angle between rows. So whenever the training objective constrains only \(AB^\top\), the per-coordinate scaling is unidentified, and cosine similarity computed on the resulting embeddings is arbitrary — a function of an optimisation accident rather than of the data.
5.4 Anisotropy: the space is not uniformly occupied
One more model-dependent property shapes how cosine scores read. Ethayarajh (2019) measured the geometry of contextual representations in ELMo, BERT and GPT-2 and found them highly anisotropic: rather than spreading over the sphere, vectors occupy a narrow cone, so even randomly chosen unrelated words exhibit substantial positive cosine similarity. In the upper layers of GPT-2 the effect was most extreme, with average similarity between random words approaching \(1\). To measure genuine contextuality the study had to subtract this baseline.
Two consequences, stated carefully:
- Absolute cosine values are not interpretable across models. A score of \(0.8\) means one thing in a near-isotropic space and something quite different in a narrow cone. Only relative ordering within one space is reliable without calibration.
- Anisotropy is a property of a specific model and layer, not a universal constant. It was measured in named models under stated conditions. Modern retrieval-tuned encoders are frequently trained in ways that reduce it, and quoting a fixed numeric threshold as though it applied to all embeddings would be unsupported.
5.5 What random-vector geometry does and does not explain
There is a genuine mathematical fact about high dimension. For two vectors drawn uniformly at random from the unit sphere in \(\mathbb{R}^d\), the cosine of the angle between them has mean \(0\) and variance \(1/d\), so its standard deviation is \(1/\sqrt{d}\). At \(d=768\) that is \(1/\sqrt{768}\approx 0.036\): random directions are nearly orthogonal, and sharply concentrated about orthogonality.
- Random unit vectors are isotropic by construction. Trained embeddings are not — §5.4 shows them occupying a narrow cone, which is the opposite of the uniform assumption the \(1/\sqrt d\) result requires. A theorem about the uniform measure cannot be applied to a distribution known to violate it.
- Embedding quality is not fixed by dimension. It depends on architecture, training data, objective, fine-tuning and pooling. Asserting that scale or training cannot improve the separability of a learned space confuses a property of random vectors with an empirical property of trained models.
5.6 Small angular gaps do not imply weak semantic distinctions
Converting two cosine scores to angles is straightforward. For \(0.92\) and \(0.88\):
$$\arccos(0.92)\approx 23.07^\circ,\qquad \arccos(0.88)\approx 28.36^\circ,$$a gap of roughly \(5.3^\circ\).
6. Why Cosine Is Useful for Search
How a bounded scalar becomes a ranking — the step that turns a learned representation into a retrieval system.
6.1 The whole mechanism
Retrieval requires an ordering over documents, and an ordering requires a single comparable number per document. Cosine supplies exactly that, and its properties are what make the ordering well-defined:
- Encode each document \(D_j\) once, offline: \(v_j = \text{pool}(\text{encode}(D_j))\), normalized.
- At query time encode the query with the same model: \(u = \text{pool}(\text{encode}(Q))\), normalized.
- Score every document: \(s_j = u\cdot v_j = \cos\theta_j\).
- Sort descending and return the top \(k\).
flowchart LR Q["Query text"] --> QE["Encoder"] --> QV["u — query vector"] D["Document corpus"] --> DE["Same encoder
offline, once"] --> DV["v₁ … v_N — stored"] QV --> S["cos(u, v_j)
one scalar per document"] DV --> S S --> R["Sort descending"] --> K["Top-k results"] style S fill:#fff7e6,stroke:#9a6500,stroke-width:2px style K fill:#e8f7f1,stroke:#157a5a
6.2 Which properties of cosine the ranking actually relies on
| Property | Why ranking needs it |
|---|---|
| Bounded in \([-1,1]\) (§4.2) | Scores are comparable across queries and documents; thresholds are expressible without per-query rescaling. |
| Scale-invariant (§4.1) | A long document and a short one are not advantaged or penalised by vector magnitude alone — only by direction. |
| Total order on reals | Any set of scores sorts unambiguously, so "top \(k\)" is always well-defined. |
| Monotone in \(\theta\) | Higher score always means smaller angle; the ordering has an unambiguous geometric reading (§4.5). |
| Single inner product on normalized vectors | \(O(d)\) per comparison with no division or branching — the basis of §7. |
6.3 The ranking is relative, not absolute
Cosine turns a learned representation into a relative relevance signal. It reliably says that document \(A\) is more aligned with the query than document \(B\). It does not, without calibration, say that \(A\) is relevant — the same score may indicate a good match in one model's space and a mediocre one in another's (§5.4). Threshold-based filtering therefore requires per-model calibration against labelled data; top-\(k\) ranking does not.
7. Why Cosine Is Attractive at Scale
Cosine defines the similarity relationship. Approximate nearest-neighbour structures make searching it practical. The emphasis here is on the former.
7.1 The identity that cheapens everything
Section 4.4 established \(\hat a\cdot\hat b=\cos\theta\). Normalize once at indexing time and every subsequent comparison is a bare inner product: \(d\) multiplications and \(d-1\) additions, no square roots, no division. This is the single most consequential practical fact about cosine similarity — it is a dot product in disguise, and dot products are what hardware and BLAS libraries are built to do in bulk.
Exhaustive scoring of \(N\) documents of dimension \(d\) costs \(\Theta(Nd)\) arithmetic operations per query — linear in corpus size. At large \(N\) that is the thing to avoid, which is what ANN indexes are for.
7.2 How vector databases actually expose cosine
- Expose cosine directly as a selectable metric, computing the normalized form internally. Qdrant, Milvus and pgvector all offer a cosine metric or cosine-distance operator.
- Normalize at ingest and use inner product. This is FAISS's documented approach: it provides no dedicated cosine metric, and the canonical recipe is
faiss.normalize_L2on both corpus and query vectors followed by an inner-product index such asIndexFlatIP, at which point the returned inner products are cosine similarities. - Accept L2 on normalized vectors, relying on the monotone equivalence of §4.5 to produce the identical ranking.
7.3 ANN indexing, in the role it belongs in
Exhaustive search is exact but linear in \(N\). Approximate nearest-neighbour indexes trade a controllable amount of recall for a large reduction in the number of comparisons. HNSW — a multi-layer proximity graph in which search descends from sparse upper layers to dense lower ones, greedily following whichever neighbour improves the similarity score — is among the most widely deployed. Malkov and Yashunin report search cost scaling logarithmically with corpus size under their experimental conditions.
flowchart TB EP["Entry point
sparse top layer"] --> L2["Upper layers
long-range hops, coarse approach"] L2 --> L1["Lower layers
short hops, local refinement"] L1 --> CAND["Candidate pool
size controlled by ef"] CAND --> OUT["Top-k by cosine"] style EP fill:#e8f1ff,stroke:#3975c6 style CAND fill:#fff7e6,stroke:#9a6500 style OUT fill:#e8f7f1,stroke:#157a5a,stroke-width:2px
Two parameters express the tradeoff. \(M\) governs graph connectivity at build time; \(\mathit{ef}\) governs how many candidates the search keeps in flight. Raising either increases recall and cost. The right values are found by measuring recall against exhaustive search on representative data — not by quoting defaults.
8. Where Single-Vector Cosine Retrieval Has Limits
The limits belong to the single-vector representation, not to the cosine function. Naming the right culprit determines the right remedy.
8.1 The architectural constraint
In the §6.1 design, \(v_j\) is computed before any query exists. This is precisely what makes precomputation and ANN indexing possible — and it imposes a hard constraint:
8.2 What follows from it
- A fixed-capacity bottleneck. A passage containing several distinct claims must be represented by one direction. Aspects of it that no training signal emphasised may not be recoverable, whatever metric is applied afterwards.
- No token-level interaction at scoring time. Fine-grained correspondence between a query phrase and a specific document clause is not available to a single dot product between pooled vectors.
- Query-dependent emphasis is impossible. If relevance hinges on a minor detail of a long passage, the pooled vector may have given that detail little weight.
8.3 Negation, stated carefully
The defensible statement is narrower: whether a particular model's embeddings reliably separate a statement from its negation is an empirical property of that model, determined by whether its training data and objective required the distinction. Contrastive training that never presents negation pairs as hard negatives has no reason to encode the distinction strongly. This is a limitation to be measured on a given model, not deduced from pooling arithmetic.
8.4 The cross-encoder: dropping the independence property
If the constraint is independent encoding, the remedy is joint encoding. A cross-encoder takes the concatenated pair \((Q, D_j)\) as a single input and emits a relevance score directly. Attention spans both texts, so every document token is read in the presence of the query.
flowchart TB
subgraph BI["Bi-encoder — independent encoding"]
BQ["Query"] --> BQE["Encoder"] --> BQV["u"]
BD["Document"] --> BDE["Encoder
offline"] --> BDV["v"]
BQV --> BS["cos(u,v)"]
BDV --> BS
end
subgraph CE["Cross-encoder — joint encoding"]
CQ["Query + Document
concatenated"] --> CM["Transformer
attention spans both"] --> CS["Relevance score"]
end
BS --> N1["Precomputable · ANN-indexable · O(d) per comparison"]
CS --> N2["Not precomputable · one forward pass per pair"]
style BS fill:#e8f1ff,stroke:#3975c6
style CS fill:#f4eefc,stroke:#7b52b9
style N1 fill:#e8f7f1,stroke:#157a5a
style N2 fill:#fff0f0,stroke:#a93636
| Bi-encoder | Cross-encoder | |
|---|---|---|
| Encoding | Query and document separately | Jointly, as one input |
| Document vectors | Precomputed once, stored | Not applicable — no reusable representation |
| Query-time work | One encode + ANN search over \(N\) | One model forward pass per candidate pair |
| Interaction | Single dot product between pooled vectors | Full attention across both texts |
| Indexable | Yes | No |
| Scales to large corpora | Yes | No — cost grows with pairs scored |
The cost asymmetry is severe and is the reason the architectures coexist. Reimers and Gurevych (2019), introducing Sentence-BERT, report that finding the most similar pair among 10,000 sentences with BERT used as a cross-encoder takes roughly 65 hours on their hardware, because all \(\binom{10000}{2}\approx 5\times10^{7}\) pairs must be scored individually. The same task with SBERT embeddings takes about 5 seconds to encode, after which cosine comparison is near-instantaneous. That contrast is the entire economic case for embedding-based retrieval.
8.5 Reranking as an extension, not a replacement
Combining the two is straightforward and follows directly from their cost structures. Stage one uses cosine over an ANN index to reduce \(N\) documents to \(k\) candidates at a cost that does not grow with \(k\). Stage two applies the cross-encoder to those \(k\) pairs at a cost linear in \(k\) and independent of \(N\).
flowchart LR N["Corpus — N documents"] --> S1["Stage 1 · cosine + ANN
cheap, recall-oriented"] S1 --> C["k candidates
k ≪ N"] C --> S2["Stage 2 · cross-encoder
expensive, precision-oriented"] S2 --> F["Reordered top results"] style S1 fill:#e8f1ff,stroke:#3975c6 style S2 fill:#f4eefc,stroke:#7b52b9 style F fill:#e8f7f1,stroke:#157a5a,stroke-width:2px
8.6 Late interaction: the middle of the spectrum
The two architectures are endpoints of a spectrum, and it is worth seeing the middle. Late interaction approaches such as ColBERT store a vector per token rather than one per document, then compute similarity by matching query tokens against document tokens at query time. This recovers some token-level interaction while keeping document encoding query-independent and therefore precomputable. The cost is storage and a more complex retrieval procedure.
8.7 Downstream: retrieval-augmented generation
One application deserves a short mention because it is where retrieval quality becomes visible. In RAG, semantic retrieval selects the context supplied to a generative model. The retrieval stage determines what the generator is given; context that was never retrieved cannot inform the output. Weak retrieval therefore constrains achievable generation quality.
9. Beyond Cosine: Alternatives and Their Conditions
Cosine is not mathematically mandatory. Its prevalence has specific, nameable causes.
9.1 The alternatives
| Function | Definition | Sensitive to magnitude? | When appropriate |
|---|---|---|---|
| Cosine similarity | \(\dfrac{a\cdot b}{\lVert a\rVert\lVert b\rVert}\) | No | Magnitude should not influence similarity; model trained with cosine objective |
| Inner product | \(a\cdot b\) | Yes | Magnitude is meaningful — e.g. encodes confidence, popularity or a learned prior the model was trained to express |
| Euclidean distance | \(\lVert a-b\rVert\) | Yes | Absolute position in the space matters; equivalent to cosine ranking if normalized (§4.5) |
| Angular distance | \(\theta/\pi\) | No | Same ordering as cosine, but satisfies the triangle inequality (§4.6) |
| Learned / task-specific | e.g. a cross-encoder's scoring head | n/a | Richer interaction is needed and cost permits (§8.4) |
9.2 Why cosine is nonetheless so common
Not because it is superior in general, but because several desirable properties coincide in it:
Text length and magnitude artefacts do not dominate similarity (§4.1).
\([-1,1]\) for every pair, making scores comparable without rescaling (§4.2).
Means one definite thing — angular alignment — with an unambiguous reading at \(+1\), \(0\), \(-1\).
Reduces to a plain inner product on normalized vectors, which hardware does exceptionally well (§7.1).
And decisively: it is the function most embedding models for retrieval are trained with (§5.2). Using at inference the similarity the objective optimised is not a stylistic preference but a correctness consideration — §5.3 shows what can go wrong otherwise. Where magnitude carries genuine learned information, the unnormalized inner product may be the better choice, and normalizing would discard signal.
10. Conclusion
The hierarchy the argument has established.
Cosine similarity occupies a precise position in semantic search, and most confusion about it comes from assigning it a different one. It is not a semantic operator. It is not an approximation to understanding. It is a bounded, scale-invariant measurement of angular alignment, derived in §4 from the law of cosines and carrying no knowledge of language whatsoever.
What makes it indispensable is what sits beneath it. An embedding model, trained under an objective that rewards similarity structure, produces a space in which semantic relationships have become geometric ones. In that space — and only in that space — measuring an angle recovers something about meaning. The metric contributes rigour and cheapness; the model contributes the semantics.
- The embedding model creates the semantic geometry.
- Cosine similarity measures directional alignment within that geometry.
- The similarity score enables semantic ranking.
- Vector indexes make that ranking scalable.
- Reranking adds richer interaction when a single-vector representation is insufficient.
Each layer depends on the one above and cannot substitute for it. A better metric cannot repair a poorly trained space. A larger index cannot create relevance that the representation failed to encode. A reranker cannot retrieve what the first stage never surfaced. And cosine similarity — the single division that this entire architecture rests on — works not because it is clever, but because a model was trained to make it informative.
Appendix A · Question Index
Each question the paper sets out to answer, and where it is answered.
| # | Question | Answered in |
|---|---|---|
| 1 | What is an embedding? | §2.1, §2.5 |
| 2 | How does text become a vector representation? | §2.2–§2.4 |
| 3 | What does a vector geometrically represent? | §3.1–§3.2 |
| 4 | What exactly does cosine similarity measure? | §4.1–§4.3 |
| 5 | Why is the angle / direction between vectors useful? | §3.4, §4.1, §4.4 |
| 6 | Why can directional alignment correspond to semantic similarity? | §5.1–§5.2 |
| 7 | What role does the training objective play in making cosine meaningful? | §5.2–§5.3 |
| 8 | Why is cosine often preferred over the raw dot product? | §4.1, §9.1–§9.2 |
| 9 | How does cosine become a ranking mechanism? | §6.1–§6.3 |
| 10 | Why does this scale to millions of documents? | §7.1–§7.3 |
| 11 | Where does single-vector cosine retrieval work well? | §6.2, §8.4 (cost argument) |
| 12 | What are its limitations? | §8.1–§8.3 |
| 13 | Why do bi-encoders and cross-encoders both exist? | §8.4 |
| 14 | Why is reranking an extension rather than a replacement? | §8.5–§8.6 |