← Back to cipheryogi portfolio

Why Cosine Similarity Powers Semantic Search

Semantic search rests on one arithmetic act: divide a dot product by two lengths, then read the result as relevance. This paper explains what that number actually measures, why it is bounded, why direction rather than length is the quantity worth comparing, and — the crux — what has to be true of the embedding model before the angle between two vectors has anything to do with meaning.

The central claim is a division of labour. Cosine similarity does not understand language; it is a fixed geometric operation with no knowledge of anything. The embedding model builds a space in which semantic relationships are encoded as geometric ones. Cosine then measures alignment inside that learned space, and that measurement is what makes ranking — and therefore search — possible.

Overview

The argument in four moves.

Where do vectors come from?From pooled activations of a trained encoder — not from parameters, and not from any single hidden state. §2.
What does cosine measure?Directional alignment: the normalized inner product, bounded in \([-1,1]\), invariant to length. §3, §4.
Why should angle mean anything?It need not. It does when the training objective was built to make it so. This is the paper's pivot. §5.
Why does this scale?Normalization turns cosine into an inner product, which ANN indexes optimise directly. §7.

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
The question that organises everything. Among all the ways to compare two vectors — length, component-wise agreement, Euclidean proximity — why should the angle be the one that tracks meaning? The answer is not a property of cosine. It is a property of what the training process constrained, and what it left free. §3 and §4 establish what cosine measures; §5 establishes when that measurement is meaningful.

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.

ObjectWhat it isChanges per input?
Parameters (weights)Numbers learned during training and frozen at inference. Includes the input embedding matrix — one static vector per vocabulary token.No
ActivationsValues computed inside the network while processing one input.Yes
Hidden statesThe per-token activations at a given layer. For an \(n\)-token input: \(n\) vectors, not one.Yes
Pooled representation / embeddingThe \(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.

On "compression." An embedding is better described as a fixed-dimensional learned representation than as compression. Its dimensionality \(d\) is an architectural choice fixed before any text is seen — the model must express every input in exactly \(d\) numbers whether the input is three words or three hundred. That is a representational bottleneck: the training objective decides which distinctions are worth the budget. Calling it compression invites the wrong inference, namely that a better codec would recover the lost detail.

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.

Attention is not universally all-to-all. It is often said that "every token reads every other token." That holds for bidirectional encoders (BERT-style), where the attention mask permits every position to attend to every other. It does not hold for causal / decoder-only models, whose mask permits position \(i\) to attend only to positions \(\le i\). Which positions are visible is a property of the mask, and the mask is an architectural choice. Encoder-only, decoder-only and prefix-LM architectures therefore contextualize differently — a distinction that matters when choosing how to pool.

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

A hidden state is not automatically a good embedding, nor automatically a bad one. Taking an arbitrary hidden state from a model never trained for similarity often yields a weak semantic embedding, because nothing in its objective required geometric proximity to track meaning. But this is model- and method-specific, not a law. Decoder-only models can be, and routinely are, fine-tuned into strong embedding models through contrastive or related objectives plus an appropriate pooling and normalization scheme. Stated precisely: whether a representation is useful for semantic similarity depends on the training objective, the extraction point, and the pooling rule — not on whether the architecture is an encoder or a decoder.

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.

A coincidence worth naming. Here \(\lVert A-B\rVert\) and \(\lVert A\rVert\) coincide only because \(B=2A\) forces \(B-A=A\) exactly. With \(B=3A\) the distance is \(\lVert 2A\rVert=2\sqrt{38}\approx 12.33\), while \(\lVert A\rVert\) is unchanged at \(6.164\). The two quantities must therefore be computed separately: raw Euclidean distance is magnitude-sensitive, and that fact is established by the distance itself, never by substituting a norm for it.

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\):

$$\lVert a-b\rVert^2=\lVert a\rVert^2+\lVert b\rVert^2-2\lVert a\rVert\lVert b\rVert\cos\theta$$

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 meaningRetrieval 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
A caution about the negative range. That \(\cos\theta\in[-1,1]\) is mathematical fact. That the negative range is used by a given embedding model is not. Many trained text encoders produce vectors occupying a restricted region of the sphere, so observed similarities between real texts may span a far narrower interval than \([-1,1]\) — and a score of \(0\) need not mean "unrelated" in such a space. The bound is universal; the distribution within it is model-specific (§5.4).

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.

a b

Drag the circular handles. Hold Shift while dragging to snap to integers.

Components

a(4.00, 1.00)
b(-1.00, 3.00)

The dot product

4.00(-1.00) + 1.00(3.00) = -1.00
a · b-1.00
‖a‖4.12
‖b‖3.16

Divide by both lengths

-1.00 / (4.12 × 3.16)
cos θ-0.077
θ94.4°
Obtuse — negative dot product

What normalization discards

â(0.97, 0.24)
b̂(-0.32, 0.95)
â · b̂-0.077

On unit vectors the inner product is the cosine — no division remains. Press Scaled ×10: both lengths change by a factor of ten and cos θ does not move at all. That invariance is the property §5 depends on.

Guess before you scroll Press Parallel (\(a=(3,2)\), \(b=(6,4)\)). The two arrows have visibly different lengths. Does \(\cos\theta\) read \(1.000\), or something slightly below it?

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:

$$\lVert \hat a-\hat b\rVert^{2}=\lVert \hat a\rVert^{2}-2(\hat a\cdot\hat b)+\lVert \hat b\rVert^{2}=1-2\cos\theta+1=2-2\cos\theta$$

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.

The practical consequence. For normalized embeddings, "cosine versus Euclidean" is not a modelling decision; the two induce the same ranking, so a vector index offering only L2 can serve cosine queries exactly. Assumption: this equivalence requires normalization. On un-normalized vectors the two orderings genuinely differ, because \(\lVert a\rVert\) and \(\lVert b\rVert\) no longer cancel. The question that matters is whether you normalized — not which formula you typed.

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?

The central insight of this paper.
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.

This is the answer to §5.1. Angle tracks meaning because the objective that produced the vectors was written in terms of angle. Train with cosine in the loss and you get a space where cosine is informative; train with an unnormalized inner product and the magnitudes carry information that cosine will discard. Use at inference the similarity function the model was optimised for. Steck et al. (2024) make the same recommendation from the opposite direction: when a model is not trained for cosine, cosine on its embeddings can be arbitrary (§5.3).
Not the only route. Contrastive learning is widely used but is not the only way to shape a usable embedding space. Related objectives — multiple-negatives ranking, distillation from a stronger model, masked-language pretraining followed by supervised similarity fine-tuning, and others — also produce spaces in which angular comparison is informative. The accurate claim is that some objective must make similarity structure part of what is optimised; it is not that one particular loss is mandatory.

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.

What this does and does not establish. It does not show cosine similarity is inherently flawed. It shows cosine is only meaningful when something pins down the scaling freedom — which is exactly what training with cosine in the loss, or normalizing during training, accomplishes. The result is derived for linear/MF models; the authors note that deep models trained with different regularization carry analogous, if less analytically tractable, freedoms. Read correctly, this is the sharpest available statement of §5.2: cosine is meaningful when the model was built for it.

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.

Why this does not explain real retrieval score distributions. It is tempting to invoke random-vector concentration as the mechanism behind observed score bunching in semantic search, and to conclude that no amount of model scaling can repair it. Both steps overreach.
  • 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.
What the random-vector result legitimately provides is geometric intuition: in high dimension, directions are plentiful and near-orthogonality is the generic case, which is why a \(d\)-dimensional space can host many distinguishable concepts. Explaining any particular model's score distribution requires measuring that model.

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\).

What the arithmetic does not license. The computation above is exact. The inference sometimes drawn from it — that a small angular gap means the semantic distinction is weak or unreliable — does not follow. Cosine is a nonlinear function of angle: near \(\theta=0\) its derivative \(-\sin\theta\) is small, so large score differences correspond to small angular ones, and the mapping from either quantity to semantic importance is set by the model's training, not by geometry. A \(5^\circ\) separation may be a decisive, well-calibrated distinction in a space trained to make exactly that distinction. Geometry alone establishes no semantic significance in either direction.

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:

  1. Encode each document \(D_j\) once, offline: \(v_j = \text{pool}(\text{encode}(D_j))\), normalized.
  2. At query time encode the query with the same model: \(u = \text{pool}(\text{encode}(Q))\), normalized.
  3. Score every document: \(s_j = u\cdot v_j = \cos\theta_j\).
  4. 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

PropertyWhy 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 realsAny 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.
The same encoder on both sides. Query and document vectors must come from the same space, or the angle between them is meaningless. Asymmetric setups exist — some models use distinct query and document encoders trained jointly so their outputs are co-embedded in one space — but mixing two independently trained models produces scores with no interpretation. This is a correctness requirement, not a convention.

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

Production systems do expose cosine. Cosine is not a metric that production vector stores lack; it is one they reach in one of three equivalent ways:
  1. 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.
  2. 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_L2 on both corpus and query vectors followed by an inner-product index such as IndexFlatIP, at which point the returned inner products are cosine similarities.
  3. Accept L2 on normalized vectors, relying on the monotone equivalence of §4.5 to produce the identical ranking.
All three compute the same ordering. The engineering question is where normalization happens, not whether cosine is supported.

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
What is deliberately not claimed here. No closed-form expression of the kind \(C\approx 2(\mathit{ef}\times M\times d)\) is offered as HNSW's complexity, and no specific recall percentage is attached to a specific \(\mathit{ef}\) value. Such an expression is at best an illustrative sketch of one implementation's inner loop rather than the algorithm's complexity; and recall at a given \(\mathit{ef}\) depends on the dataset, the construction parameters and the intrinsic dimensionality of the data, so no universal numbers exist. The logarithmic scaling reported by Malkov and Yashunin is an empirical result under stated conditions, not a proven worst-case bound. For this paper's argument only the qualitative point is needed: cosine defines the similarity relationship; the index makes searching that relationship tractable without altering what is being measured.

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:

The independence property. Document and query are encoded separately. The document's representation therefore cannot depend on the query. Whatever the encoder chose to preserve when compressing a passage into \(d\) numbers, it chose without knowing what would be asked. This is a property of the bi-encoder architecture, not of cosine similarity: swapping in any other similarity function over the same two independent vectors changes nothing about it.

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

Why the dilution argument fails. Negation is sometimes said to fail because "not" is merely one token among many in an average, so its contribution is diluted. That reasoning does not hold: in a Transformer encoder, representations are contextual, and a negation token can alter the representation of every token it attends to. "Safe" in "this is not safe" is not the same vector as "safe" in "this is safe" before pooling ever happens.

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-encoderCross-encoder
EncodingQuery and document separatelyJointly, as one input
Document vectorsPrecomputed once, storedNot applicable — no reusable representation
Query-time workOne encode + ANN search over \(N\)One model forward pass per candidate pair
InteractionSingle dot product between pooled vectorsFull attention across both texts
IndexableYesNo
Scales to large corporaYesNo — 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.

What is not claimed. Cross-encoders are not universally superior, and no fixed percentage improvement is quoted here. Published results generally show joint encoding ranking better than independent encoding on the same candidates for many retrieval tasks, but the margin is task-, model- and data-dependent. Whether it is worth the cost is an empirical question answered per application.

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
The relationship, stated precisely. Reranking extends embedding retrieval; it does not replace the semantic-vector paradigm. The reranker never sees the corpus — it only ever sees candidates that cosine retrieval already surfaced. Its ceiling is therefore set by stage-one recall: a document cosine never retrieved cannot be rescued by any reranker. Far from superseding cosine retrieval, the second stage depends on it.
Reranking is not required. Two-stage retrieval is not a requirement, and no equation of the form "end-to-end quality \(= R_k \times P\)" holds as a general law. First-stage vector retrieval provides scalable candidate generation and is sufficient on its own for many applications. Reranking should be added when measured gains in ranking quality — or in a downstream task — justify its additional compute and latency. Any such product form presumes a single relevant document and independence between the stages' error events; it is not a general identity and is not used here.

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.

Why it belongs here in one paragraph. It locates the design space precisely: one vector per document (maximum precomputation, minimum interaction) → many vectors per document (partial interaction, still precomputable) → joint encoding (maximum interaction, no precomputation). All three still compute inner products between learned representations. Even at the interactive end, the underlying paradigm is unchanged — which is the point.

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.

Stated without overreach. It does not follow that a generator deterministically produces a wrong answer from imperfect context — models may abstain, hedge, rely on parametric knowledge, or succeed from partial evidence. The defensible claim is directional: retrieval quality bounds the evidence available downstream. Quantifying the effect requires end-to-end evaluation of the specific system.

9. Beyond Cosine: Alternatives and Their Conditions

Cosine is not mathematically mandatory. Its prevalence has specific, nameable causes.

9.1 The alternatives

FunctionDefinitionSensitive to magnitude?When appropriate
Cosine similarity\(\dfrac{a\cdot b}{\lVert a\rVert\lVert b\rVert}\)NoMagnitude should not influence similarity; model trained with cosine objective
Inner product\(a\cdot b\)YesMagnitude is meaningful — e.g. encodes confidence, popularity or a learned prior the model was trained to express
Euclidean distance\(\lVert a-b\rVert\)YesAbsolute position in the space matters; equivalent to cosine ranking if normalized (§4.5)
Angular distance\(\theta/\pi\)NoSame ordering as cosine, but satisfies the triangle inequality (§4.6)
Learned / task-specifice.g. a cross-encoder's scoring headn/aRicher 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:

Scale invariance

Text length and magnitude artefacts do not dominate similarity (§4.1).

Bounded range

\([-1,1]\) for every pair, making scores comparable without rescaling (§4.2).

Geometric clarity

Means one definite thing — angular alignment — with an unambiguous reading at \(+1\), \(0\), \(-1\).

Computational match

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 hierarchy, in order:
  1. The embedding model creates the semantic geometry.
  2. Cosine similarity measures directional alignment within that geometry.
  3. The similarity score enables semantic ranking.
  4. Vector indexes make that ranking scalable.
  5. 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.

The distinction worth carrying away. Cosine similarity does not understand semantics; it is a mathematical operation. The embedding model creates a representation space in which semantic relationships can be encoded. Cosine then measures directional alignment within that learned space. Keeping these three statements separate resolves most of the apparent paradoxes in the subject — including why cosine is simultaneously so effective in practice and provably arbitrary in the wrong setting (§5.3).

Appendix A · Question Index

Each question the paper sets out to answer, and where it is answered.

#QuestionAnswered in
1What is an embedding?§2.1, §2.5
2How does text become a vector representation?§2.2–§2.4
3What does a vector geometrically represent?§3.1–§3.2
4What exactly does cosine similarity measure?§4.1–§4.3
5Why is the angle / direction between vectors useful?§3.4, §4.1, §4.4
6Why can directional alignment correspond to semantic similarity?§5.1–§5.2
7What role does the training objective play in making cosine meaningful?§5.2–§5.3
8Why is cosine often preferred over the raw dot product?§4.1, §9.1–§9.2
9How does cosine become a ranking mechanism?§6.1–§6.3
10Why does this scale to millions of documents?§7.1–§7.3
11Where does single-vector cosine retrieval work well?§6.2, §8.4 (cost argument)
12What are its limitations?§8.1–§8.3
13Why do bi-encoders and cross-encoders both exist?§8.4
14Why is reranking an extension rather than a replacement?§8.5–§8.6