Vector search finds the items whose meaning sits closest to your query — by distance in an embedding space, not by matching words. The toy above measures the query against every point; real systems do the same, then cheat with an index so it stays fast at a billion points.
Where you meet it
- The retrieve step of RAG — pull the chunks nearest a question, feed them to an LLM.
- Semantic search, recommendations, dedup, image and audio similarity.
- Vector databases (Pinecone, Weaviate, Milvus) and libraries like FAISS.
What it does
An embedding model turns each document into a vector — a point in a space of hundreds or thousands of dimensions, where nearby points mean similar things. Your query becomes a vector too. k-NN returns the k vectors closest to it: the k nearest neighbours.
At a billion vectors you stop searching exactly — an ANN index trades a little recall for an enormous speedup.
How it works
Conceptually it is three steps:
- Embed the query into a vector
q. - Compute a distance (or similarity) from
qto the stored vectors. - Sort and return the
ksmallest distances.
Done exactly, that is brute force: every query touches every vector, costing O(N · d) for N vectors of dimension d. Fine for thousands, hopeless for billions. So real systems build an ANN index (Approximate Nearest Neighbour) that trades a little accuracy for a large speedup:
- HNSW — a multi-layer proximity graph. The search starts in a sparse top layer that covers big jumps, then greedily descends into denser layers, giving roughly logarithmic search instead of linear (Malkov & Yashunin, 2016).
- IVF — cluster the vectors, then at query time scan only the few clusters nearest the query (
nprobeof them), skipping the rest. Often paired with product quantization to compress vectors in memory.
import faiss, numpy as np
xb = np.random.rand(1_000_000, 128).astype('float32') # database
q = np.random.rand(1, 128).astype('float32') # query
index = faiss.IndexHNSWFlat(128, 32) # M = 32 graph links
index.add(xb)
D, I = index.search(q, k=5) # 5 nearest — approximate, fast
Watch out
- ANN is approximate. You tune a recall vs speed trade-off (e.g. HNSW
efSearch, IVFnprobe): higher = more accurate, slower. Measure recall against a brute-force baseline. - The metric must match the embedding. Models trained for cosine similarity misbehave under raw L2. Normalise vectors, or pick the right metric — cosine, dot product, or Euclidean.
- Curse of dimensionality. In very high dimensions distances concentrate and "nearest" gets fuzzy; good embeddings plus the right metric matter more than raw dimension count.
- Build & update cost. Graph indexes like HNSW are memory-hungry and slow to build; deletes and heavy updates often mean periodic rebuilds.
Go deeper
Vektor-Suche findet die Einträge, deren Bedeutung deiner Query am nächsten liegt — über Distanz im Embedding-Raum, nicht über Wortabgleich. Das Spielzeug oben misst die Query gegen jeden Punkt; echte Systeme tun dasselbe, schummeln dann aber mit einem Index, damit es auch bei Milliarden Punkten schnell bleibt.
Wo es vorkommt
- Der Retrieve-Schritt von RAG — die Chunks nahe einer Frage holen und einem LLM geben.
- Semantische Suche, Empfehlungen, Dedup, Bild- und Audio-Ähnlichkeit.
- Vektordatenbanken (Pinecone, Weaviate, Milvus) und Bibliotheken wie FAISS.
Was es tut
Ein Embedding-Modell macht aus jedem Dokument einen Vektor — einen Punkt in einem Raum mit Hunderten bis Tausenden Dimensionen, in dem nahe Punkte Ähnliches bedeuten. Deine Query wird ebenfalls ein Vektor. k-NN liefert die k Vektoren, die ihm am nächsten sind: die k nächsten Nachbarn.
Bei einer Milliarde Vektoren suchst du nicht mehr exakt — ein ANN-Index tauscht ein wenig Recall gegen enormen Speed.
Wie es funktioniert
Im Kern sind es drei Schritte:
- Die Query in einen Vektor
qeinbetten. - Eine Distanz (oder Ähnlichkeit) von
qzu den gespeicherten Vektoren berechnen. - Sortieren und die
kkleinsten Distanzen zurückgeben.
Exakt gerechnet ist das Brute Force: jede Query berührt jeden Vektor, Kosten O(N · d) bei N Vektoren der Dimension d. Okay für Tausende, hoffnungslos für Milliarden. Darum bauen echte Systeme einen ANN-Index (Approximate Nearest Neighbour), der ein wenig Genauigkeit gegen großen Speed eintauscht:
- HNSW — ein mehrschichtiger Nachbarschaftsgraph. Die Suche startet in einer dünnen obersten Schicht für große Sprünge und steigt dann gierig in dichtere Schichten ab — grob logarithmische statt lineare Suche (Malkov & Yashunin, 2016).
- IVF — die Vektoren clustern und zur Query-Zeit nur die wenigen Cluster nahe der Query durchsuchen (
nprobedavon), den Rest überspringen. Oft kombiniert mit Product Quantization, um Vektoren im Speicher zu komprimieren.
import faiss, numpy as np
xb = np.random.rand(1_000_000, 128).astype('float32') # Datenbank
q = np.random.rand(1, 128).astype('float32') # Query
index = faiss.IndexHNSWFlat(128, 32) # M = 32 Graph-Kanten
index.add(xb)
D, I = index.search(q, k=5) # 5 nächste — approximativ, schnell
Worauf achten
- ANN ist approximativ. Du justierst einen Recall-vs-Speed-Trade-off (z. B. HNSW
efSearch, IVFnprobe): höher = genauer, langsamer. Recall gegen eine Brute-Force-Baseline messen. - Die Metrik muss zum Embedding passen. Modelle für Kosinus-Ähnlichkeit verhalten sich unter rohem L2 falsch. Vektoren normieren oder die richtige Metrik wählen — Kosinus, Skalarprodukt oder Euklid.
- Fluch der Dimensionalität. In sehr hohen Dimensionen konzentrieren sich Distanzen, „am nächsten" wird unscharf; gute Embeddings plus passende Metrik zählen mehr als die bloße Dimensionszahl.
- Build- & Update-Kosten. Graph-Indizes wie HNSW sind speicherhungrig und langsam im Aufbau; Löschungen und viele Updates bedeuten oft periodische Rebuilds.