HNSW — hop along a proximity graph

Instead of carving space into cells, HNSW links each vector to its M nearest neighbors and searches by greedy hops — always stepping to the linked neighbor closest to the query — so there are no hard cell walls and the lonely boundary point is just one more link away.

Previously

Rigid cells gave us the boundary miss. Linking each vector to its nearest neighbors and hopping greedily toward the query removes the wall entirely — the lonely point is just one more hop away. But a flat graph still has a problem: from a random start, hopping one short link at a time across a huge dataset is slow. How do we cover big distances fast and still land precisely?

Scene 06

HNSW — hop along a proximity graph

  1. Watch
  2. Try it
  3. Predict
  4. Capture
acoustic → electroniccalm → energeticLo-fi RainAcoustic Suns…Campfire FolkCoffeehouseIndie DriveSynth DawnNeon CityClub PulseRave PeakBass DropMidnight DriveGarage BeatStudy BeatsLonely SynthNow PlayingNo cell walls — each song is linked to its nearest neighbors.RECALL vs LATENCYrecallslower →FlatIVFHNSW
What to watch for

Last scene, a hard cell wall hid 'Lonely Synth' from the query. Now watch a completely different idea. The cell boundaries are gone. Instead, every song is connected by short links to the few songs nearest it in the space — a web of neighbors. To search, we start at one node and keep hopping to whichever linked neighbor is closest to the query, stepping downhill until no neighbor is any closer. Follow the path: Indie Drive → Midnight Drive → Synth Dawn → and the last hop lands on the very point the cells missed.

Continue unlocks when the animation finishes.
Implementation

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

Index.build_graph
wire each vector to its M nearest neighbors (the kNN graph)
def build_graph(vectors, M):
edges = defaultdict(set)
for v in vectors:
# M = links per node, the only knob here
near = nearest(v, vectors, k=M)
for u in near:
edges[v].add(u) # link is symmetric
edges[u].add(v)
return edges
Index.greedy_search
hop to the linked neighbor closest to the query, stop downhill
def greedy_search(query, edges, entry):
current = entry
while True:
best = min(edges[current],
key=lambda u: dist(u, query))
if dist(best, query) >= dist(current, query):
return current # no neighbor is closer
current = best # step downhill

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

Scene 06 of 15, in the The graph act — HNSW: hop a proximity graph; express-lane layers and the ef_search knee.. Link each vector to its M nearest neighbors and search by greedy hops — no hard cell walls, so the lonely boundary point is just one more link away.

Up next. Greedy hopping works, but on a billion points, taking one short step at a time from a random entry node is slow. We need express lanes — a way to leap across the space in a few big hops, then switch to small careful steps near the query. That's exactly what HNSW's layers do.

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