From f6edf9245a6a286402086459d5bc6ae81efdeef1 Mon Sep 17 00:00:00 2001 From: Andrew Kane Date: Fri, 5 Dec 2025 15:26:49 -0800 Subject: [PATCH] Added support for adaptive beam search [skip ci] --- README.md | 1 + src/hnswutils.c | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a108520..e6bdcc7 100644 --- a/README.md +++ b/README.md @@ -1282,6 +1282,7 @@ Thanks to: - [k-means++: The Advantage of Careful Seeding](https://theory.stanford.edu/~sergei/papers/kMeansPP-soda.pdf) - [Concept Decompositions for Large Sparse Text Data using Clustering](https://www.cs.utexas.edu/users/inderjit/public_papers/concept_mlj.pdf) - [Efficient and Robust Approximate Nearest Neighbor Search using Hierarchical Navigable Small World Graphs](https://arxiv.org/ftp/arxiv/papers/1603/1603.09320.pdf) +- [Distance Adaptive Beam Search for Provably Accurate Graph-Based Nearest Neighbor Search](https://arxiv.org/pdf/2505.15636) ## History diff --git a/src/hnswutils.c b/src/hnswutils.c index 8e2a42c..65de3c8 100644 --- a/src/hnswutils.c +++ b/src/hnswutils.c @@ -829,6 +829,7 @@ HnswSearchLayer(char *base, HnswQuery * q, List *ep, int ef, int lc, Relation in HnswUnvisited *unvisited = palloc(lm * sizeof(HnswUnvisited)); int unvisitedLength; bool inMemory = index == NULL; + double lambda = 0.12; if (v == NULL) { @@ -884,7 +885,7 @@ HnswSearchLayer(char *base, HnswQuery * q, List *ep, int ef, int lc, Relation in HnswSearchCandidate *f = HnswGetSearchCandidate(w_node, pairingheap_first(W)); HnswElement cElement; - if (c->distance > f->distance) + if (c->distance > f->distance * (1 + lambda)) break; cElement = HnswPtrAccess(base, c->element); @@ -904,8 +905,10 @@ HnswSearchLayer(char *base, HnswQuery * q, List *ep, int ef, int lc, Relation in HnswSearchCandidate *e; double eDistance; bool alwaysAdd = wlen < ef; + double fDistance; f = HnswGetSearchCandidate(w_node, pairingheap_first(W)); + fDistance = f->distance * (1 + lambda); if (inMemory) { @@ -920,13 +923,13 @@ HnswSearchLayer(char *base, HnswQuery * q, List *ep, int ef, int lc, Relation in /* Avoid any allocations if not adding */ eElement = NULL; - HnswLoadElementImpl(blkno, offno, &eDistance, q, index, support, inserting, alwaysAdd || discarded != NULL ? NULL : &f->distance, &eElement); + HnswLoadElementImpl(blkno, offno, &eDistance, q, index, support, inserting, alwaysAdd || discarded != NULL ? NULL : &fDistance, &eElement); if (eElement == NULL) continue; } - if (eElement == NULL || !(eDistance < f->distance || alwaysAdd)) + if (eElement == NULL || !(eDistance < fDistance || alwaysAdd)) { if (discarded != NULL) {