The vector and the distance metric
'Closest' is not one thing — L2 measures the gap between two arrowtips, cosine measures only the angle between them, and the chosen distance metric must match how the embeddings were made, or every neighbor it returns is silently wrong.
Now that we can measure how close any two vectors are, we finally have a precise definition of 'the true nearest neighbors'. The next problem: that brute-force scan from scene 1 is the only thing that gets those neighbors perfectly right — so before we make anything faster, we need a way to MEASURE how much correctness a faster method gives up.
Scene 02
The vector and the distance metric
- Watch
- Try it
- Predict
- Capture
A vector (the list of numbers we turned each song into last scene) can be drawn as an arrow from the origin — its direction and its length both carry meaning. Watch the blue 'Now Playing' query arrow and the 'Big Wave' arrow beside it: Big Wave points almost the SAME direction but is much longer. Now ask 'how close are these?' two honest ways at once. The violet wedge measures only the angle between the arrows — tiny, so it says 'near-perfect match'. The amber line measures the gap between the two arrowtips — big, so it says 'far apart'. Same two arrows, two opposite verdicts. There is no single 'closest'; there's a CHOICE of metric.
Highlighted lines are the ones running in the diagram right now.
def l2(q, v): # tip gapreturn sqrt(sum((qi - vi)**2for qi, vi in zip(q, v)))def dot(q, v): # angle and lengthreturn sum(qi * vi for qi, vi in zip(q, v))def cosine(q, v): # angle onlyreturn dot(q, v) / (norm(q) * norm(v))
def ingest(vectors):for v in vectors:if NORMALIZE:v = v / norm(v) # onto the unit circlestore(v)# on unit-length vectors:# cosine(q, v) == dot(q, v)# argmax dot == argmin l2
def top_k(query, k):q = query / norm(query) if NORMALIZE else queryscored = []for v in stored_vectors:if METRIC == 'l2': s = -l2(q, v)elif METRIC == 'dot': s = dot(q, v)else: s = cosine(q, v)scored.append((s, v))scored.sort(reverse=True) # higher score = closerreturn scored[:k]
Where this sits in Build a vector database (Pinecone / Weaviate / pgvector style)
Scene 02 of 15, in the Why vectors act — Why a billion-vector exact scan can't hit 10 ms, and what 'closest' even means.. 'Closest' isn't one thing — L2 is the gap between arrowtips, cosine is the angle — and a metric that mismatches the embedding silently returns garbage. Normalize once and they agree.
Up next. We have a definition of correct, but no scorecard. Let's build the simplest possible 'index' — one that just runs the brute-force scan — call its perfect result the baseline, and use it to define the two numbers every faster trick will be judged on.
All 15 scenes in Build a vector database (Pinecone / Weaviate / pgvector style) · Every curriculum