1583 words
8 minutes
RAG & Vector Database

There is a chronological evolution in academics that lays the foundations of vector database.

  1. Product Quantization for Nearest Neighbor Search
  2. The Graph Standard: HNSW: Multi-layer skip-list graph topologies, logarithmic search complexity in high dimensions, beam search heuristic, and trade-offs between connectivity degree MM and exploration depth efSearch.
  3. Billion-scale similarity search with GPUs
  4. DiskANN: Fast Accurate Billion-point Nearest Neighbor Search on a Single Node

The Graph Standard: HNSW#

Paper link

Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs

The constantly growing amount of the available information resources has led to high demand in scalable and efficient similarity search data structures. One of the generally used approaches for information search is the KK-Nearest Neighbor Search (KK-NNS). Unfortunately, the complexity of the naïve approach scales linearly with the number of stored elements making it infeasible for large-scale datasets.

To overcome this problem a concept of Approximate Nearest Neighbors Search (KK-ANNS) was proposed.

Approximate Nearest Neighbor Search (KK-ANNS) Algorithm#

KK-Nearest Neighbor Search (KK-NNS) is the formal problem of retrieving the KK points in a dataset closest to a query point under a specified metric space (X,d)(X, d), whereas KK-Approximate Nearest Neighbor Search (KK-ANNS) relaxes this guarantee by trading mathematical exactness for sub-linear query time in high dimensions.

In exact KK-NNS, given:

  • A finite dataset S⊂XS \subset X of size ∣S∣=N\vert{}S\vert{} = N, where X⊆RDX \subseteq \mathbb{R}^D
  • A distance metric d:X×X→[0,∞)d: X \times X \to [0, \infty) (e.g., Euclidean distance L2L_2, Cosine distance, or Manhattan distance L1L_1)
  • A query vector q∈Xq \in X and integer K≥1K \ge 1

Exact KK-NNS finds a subset R⊆SR \subseteq S of cardinality ∣R∣=K\vert{}R\vert{} = K such that:

∀u∈R,∀v∈S∖R:d(q,u)≤d(q,v) \forall u \in R, \quad \forall v \in S \setminus R: \quad d(q, u) \le d(q, v)

For exact search, traditional space-partitioning structures such as k-dk\text{-d} trees or RR-trees require traversing nearly all bounding boxes once the intrinsic dimensionality D≳20D \gtrsim 20. As DD grows large, the relative difference between the distance to the nearest neighbor and the furthest neighbor approaches zero (lim⁡D→∞dmax⁡−dmin⁡dmin⁡→0\lim_{D \to \infty} \frac{d_{\max} - d_{\min}}{d_{\min}} \to 0) and partitioning methods degrade to an exhaustive linear scan with computational complexity O(N⋅D)\mathcal{O}(N \cdot D), both result in the Curse of Dimensionality.

To bypass such linear scaling, KK-ANNS permits an approximation error ϵ>0\epsilon > 0. In the standard (1+ϵ)(1 + \epsilon)-ANN definition, the algorithm returns a point v∈Sv \in S such that:

d(q,v)≤(1+ϵ)⋅d(q,v∗) d(q, v) \le (1 + \epsilon) \cdot d(q, v^*)

where v∗v^* is the true nearest neighbor. In practical retrieval, this accuracy is measured empirically via Recall@KK:

Recall@K=∣Rapprox∩Rtrue∣K\color{green} \boxed{\text{Recall}@K = \frac{\vert{}R_{\text{approx}} \cap R_{\text{true}}\vert{}}{K}}

where RapproxR_{\text{approx}} is the set of KK points returned by the index, and RtrueR_{\text{true}} is the ground-truth exact set computed via brute-force search.

How KK-ANNS Works Under the Hood#

All KK-ANNS algorithms avoid scanning every vector by pruning the search space ahead of time using one of 4 foundational paradigms:

  1. Tree-Based Space Partitioning (KD-Trees/Ball Trees/RP-Trees)

    Recursively bisects the vector space into hierarchical bounding volumes. k-dk\text{-d} trees split space using axis-aligned orthogonal hyperplanes, Ball trees partition space using nested hyper-spheres, and Random Projection (RP) trees (like Spotify’s Annoy) split points using hyperplanes oriented along random directions.

    Traversal descends the tree from the root to the leaf cell containing query qq in O(log⁡N)\mathcal{O}(\log N) time, then backtracks across parent branches using priority queues to evaluate intersecting bounding regions.

    Backtracking stops after visiting an inspection limit of leaf nodes (search_k). While exact branch-and-bound works well in low dimensions (D≲20D \lesssim 20), high-dimensional queries intersect almost every bounding boundary, forcing tree search to approximate aggressively or degrade toward exhaustive scan.

  2. Locality-Sensitive Hashing (LSH)

    Uses hash functions designed so that collision probability is directly proportional to vector similarity:

    P[h(u)=h(v)]=sim(u,v) P[h(u) = h(v)] = \text{sim}(u, v)

    During search, query point qq is hashed into multiple hash buckets; only items sharing buckets with qq are evaluated.

  3. Inverted File and Quantization (IVF-PQ)

    The space is partitioned into CC Voronoi cells using kk-means centroids. Each vector is assigned to its nearest centroid (an Inverted File list, or IVF).

    At query time, qq is compared only to the CC centroids. The algorithm selects the closest nproben_{\text{probe}} centroids and inspects only the vectors residing in those specific lists. Vectors within lists are compressed via Product Quantization (PQ), splitting vectors into sub-vectors and estimating distances through lookup tables (Asymmetric Distance Computation).

  4. Points are vertices in a directed graph; edges connect spatial neighbors.

    Search operates as a greedy best-first traversal. Starting at an entry node, the algorithm evaluates distances to all outgoing neighbors of the current node, hopping to whichever neighbor is closest to qq. Traversal halts when local greedy steps no longer reduce the distance to qq within a candidate priority queue (beam search).

TIP

Graph-based methods achieve higher recall at lower latency than inverted files, but require significant index build time (O(Nlog⁡N)\mathcal{O}(N \log N) distance computations) and hold substantial memory overhead for adjacency lists.

The power-law scaling of the proximity graph routing in NSW, however, causes extreme performance degradation in case of low dimensional or clustered data, which is why the Hierarchical Navigable Small World (Hierarchical NSW, HNSW) comes into play.

Hierarchical NSW#

The paper proposed the Hierarchical Navigable Small World (Hierarchical NSW, HNSW), a new fully graph based incremental K-ANNS structure, which can offer a much better logarithmic complexity scaling.

The idea of Hierarchical NSW algorithm is to separate the links according to their length scale into different layers and then search in a multilayer graph.

In such structure the search starts from the upper layer which has only the longest links (the “zoom-in” phase). The algorithm greedily traverses through the elements from the upper layer until a local minimum is reached. After that, the search switches to the lower layer (which has shorter links), restarts from the element which was the local minimum in the previous layer and the process repeats.

Illustration of the Hierarchical NSW idea. The search starts from an element from the top layer (shown red). Red arrows show direction of the greedy algorithm from the entry point to the query (shown green).

Constructing the Hierarchical Layers#

When a vector is inserted, the algorithm assigns it a ceiling layer index l∈{0,1,2,… }l \in \{0, 1, 2, \dots\}. For example, if an element receives level l=2l = 2, it exists in Layer 0, Layer 1, and Layer 2. Every single vector exists at Layer 0 (the ground floor, which contains 100% of the dataset). Higher layers contain progressively smaller subsets of vectors.

Within any given layer, points are connected only to their spatial neighbors relative to the points present in that layer. To ensure higher layers become exponentially sparser, the level ll is drawn from an exponential distribution controlled by a scale parameter mLm_L:

l=⌊−ln⁡(uniform(0,1))⋅mL⌋ l = \lfloor -\ln(\text{uniform}(0, 1)) \cdot m_L \rfloor

where mL≈1ln⁡(M)m_L \approx \frac{1}{\ln(M)}, and MM is the target number of outgoing links per node. The probability behavior under this setup is such that the probability that a point reaches layer ll is P(level≥l)=e−l/mL≈M−lP(\text{level} \ge l) = e^{-l / m_L} \approx M^{-l}. If M=16M = 16, for example, roughly 11 in every 1616 vectors reaches Layer 1, 11 in every 256256 reaches Layer 2, and so on. The result is that the total number of layers scales as O(log⁡N)\mathcal{O}(\log N), keeping the index compact and preventing top layers from becoming cluttered.

The search procedure is an iterative greedy search starting from the top layer and finishing at the zero layer.

Yahoo Vespa#

Long before “vector database” became industry parlance, large-scale production search engines had already implemented aspects of vector database. Yahoo’s Vespa engine, which originated inside Norwegian enterprise search firm FAST Search & Transfer before being acquired and eventually open-sourced in 2017, had integrated tensor evaluation and vector search alongside traditional inverted indexes.

RAG & Vector Database
https://blogs.openml.io/posts/rag/
Author
OpenML Blogs
Published at
2026-11-07
License
CC BY-NC-SA 4.0