The Flat index — the 100%-recall baseline

The brute-force scan, treated as a real index called 'Flat', returns the true top-k by definition, so its recall is 100% — and that perfect-but-slow point defines the two axes, recall@k and latency, that every faster index is scored against.

Previously

With a distance metric we can name the true neighbors; now we wrap the brute-force scan into an index called Flat so we have a perfect-recall yardstick. The next problem is obvious: Flat is correct but far too slow, so how do we avoid comparing the query against every single vector?

Scene 03

The Flat index — the 100%-recall baseline

  1. Watch
  2. Try it
  3. Predict
  4. Capture
↖ ideal: high recall · low latency0.000.000.250.250.500.500.750.751.001.00recall@k (up = more correct)latency (right = slower)Flat · recall@3…INDEXFlat · recall@3…current configFlat owns the top — perfect — but lives on the …Flat returns the true top-3 [11, 14, 6…] over 14 songs. One dot today; every faster index drops its own dot h…
What to watch for

Two scenes ago you watched a brute-force scan: compare the query to every stored song, one at a time, and keep the closest. That scan was never given a name — but it is, in fact, a perfectly real way to run a search. Engineers call it the Flat index: 'flat' because it keeps every vector in one plain list and walks the whole list on every query. Watch it run over our 14 songs. It touches all of them, then ranks them, and returns the genuine three closest to 'Now Playing': Midnight Drive (#11), Lonely Synth (#14), Synth Dawn (#6). Because it checked everything, it cannot be wrong — those ARE the true nearest neighbors. On the chart to the side, a single dot appears for Flat: pinned to the very top (perfectly correct) and far to the right (slow, because it looked at everything).

Continue unlocks when the animation finishes.
Implementation

Highlighted lines are the ones running in the diagram right now.

FlatIndex.search
compare the query to every vector — exact top-k
def search(query, k):
scored = []
for v in all_vectors: # touches EVERY vector
scored.append((distance(query, v), v.id))
scored.sort() # nearest first
return [id for _, id in scored[:k]]
recall_at_k
the scorecard — measured AGAINST Flat's result
def recall_at_k(approx_ids, true_ids, k):
true_set = set(true_ids[:k]) # Flat's exact top-k
hits = len(set(approx_ids[:k]) & true_set)
return hits / k # 1.0 means perfect
# Flat scored against itself is always 1.0

Where this sits in Build a vector database (Pinecone / Weaviate / pgvector style)

Scene 03 of 15, in the First index act — Flat baseline, IVF cells, and the boundary miss that bites every junior.. Wrap the brute-force scan as an index called Flat: recall 1.0 by definition. It's the yardstick every faster index is scored against — and it defines the two axes, recall@k and latency.

Up next. Flat's sin is that it compares the query to all N vectors. The first big idea is to carve the space into neighborhoods up front, then only look inside the few neighborhoods near the query — touching a fraction of the vectors instead of all of them.

All 15 scenes in Build a vector database (Pinecone / Weaviate / pgvector style) · Every curriculum

Built with Arqly
Every scene in Build a vector database (Pinecone / Weaviate / pgvector style) builds on the one before it.All 15 Build a vector database (Pinecone / Weaviate / pgvector style) scenes