Repository navigation
Add PathSeer for Adaptive and Efficient In-Memory Filtered Graph Search - #1506
Zhiyue Li (lizhiyuell) wants to merge 1 commit into
Conversation
|
@microsoft-github-policy-service agree |
There was a problem hiding this comment.
🟡 Changes recommended
Accepted start points can suppress valid results, and unannotated unwrap calls violate the CI lint configuration.
3 open issues
What changed in this PR
Adds PathSeer as a filtered-search strategy for DiskANN’s in-memory graph index, without changing the stored graph structure.
Changes:
- Implements two-phase traversal with bounded second-hop exploration and parent-aware filtering.
- Adds a provider interface for synchronous adjacency access and implements it for in-memory graphs.
- Exposes the strategy through the search API and adds focused algorithm and integration tests.
| File | Description |
|---|---|
diskann/src/provider.rs |
Defines the PathSeerGraph adjacency interface. |
diskann/src/graph/test/provider.rs |
Implements adjacency access for the test provider. |
diskann/src/graph/test/cases/pathseer.rs |
Tests second-hop discovery, empty matches, and phase-two filtering. |
diskann/src/graph/test/cases/mod.rs |
Registers PathSeer tests. |
diskann/src/graph/search/pathseer.rs |
Implements PathSeer traversal and result collection. |
diskann/src/graph/search/mod.rs |
Exports and documents the strategy. |
diskann/src/graph/index.rs |
Adds PathSeer to the search API documentation. |
diskann-providers/src/model/graph/provider/async_/inmem/provider.rs |
Implements the interface for the in-memory provider. |
diskann-providers/src/index/diskann_async.rs |
Adds a full-precision in-memory integration test. |
Review effort: Balanced
| candidates: &mut BinaryHeap<Reverse<Scored<I>>>, | ||
| results: &mut BinaryHeap<Scored<I>>, | ||
| ) { | ||
| if results.len() == l && point.distance >= results.peek().unwrap().distance { |
| for point in starts { | ||
| scratch.visited.insert(point.id); | ||
| admit(point, l, &mut candidates, &mut results); |
| if !phase_two { | ||
| let mut remaining = budget; | ||
| for &parent in direct.iter() { | ||
| if remaining == 0 || accessor.terminate_early() { |
|
Thanks for the contribution Zhiyue Li (@lizhiyuell), the results look promising! Magdalen Dobson Manohar (@magdalendobson) - do you have any thoughts here? |
|
Thanks for this PR, Zhiyue Li (@lizhiyuell)! I agree that the algorithm is interesting and the results look promising. Thanks for using the datasets that we use in our previous evaluations and for submitting reasonably high-quality code that is easy to follow. We are interested in working towards including at least some of your contribution on our main branch. I looked over the code and algorithm descriptions, and from what I can tell there are a few separate ideas going on:
I think it would be helpful to see if you agree with this characterization, and if so, could we work on benchmarking these ideas separately? Since some of these ideas, especially the phase differentiation, add a lot of code complexity, I think the next step for our understanding would be to benchmark these ideas separately and understand how much they contribute to the speedup. I'm not sure if you have looked at our A separate note. Since so many of these transitions and stopping criteria rely on finding Thanks again, and let me know if you are open to the exploration that I propose. |


Reference Issues/PRs
None.
What does this implement/fix? Briefly explain your changes.
This PR introduces PathSeer, an efficient filtered graph search strategy for DiskANN's in-memory index, based on our research.
Building upon our research, we further adapt and improve PathSeer to work natively with DiskANN's existing graph index, without requiring any modifications to the index structure.
We evaluate PathSeer using the same two workloads as DiskANN's official filtered search benchmarks. PathSeer consistently achieves a better recall–throughput trade-off than existing methods, achieving 1.11–2.18× throughput (1.46× on average) at a target recall of 0.90 and 1.12–2.15× throughput (1.42× on average) at a target recall of 0.95, compared with the best-performing baseline for each workload.
PathSeer has also demonstrated its effectiveness in vector databases, as highlighted in Weaviate's blog.
The core idea of PathSeer is to selectively compute distances for vectors that do not satisfy the filter predicate, allowing them to serve as bridges during graph traversal, while opportunistically applying filtering to reduce unnecessary distance computations.
PathSeer employs a two-stage search strategy:
Stage 1: Compute distances for all direct neighbors while exploring a bounded number of second-hop neighbors using pre-filtering to discover more valid candidates.
Stage 2: Once the filtered result heap is full, stop second-hop exploration and apply parent-aware filtering, where a neighbor participates in distance computation if either the neighbor or its parent satisfies the filter predicate.
Any other comments?
Experimental setup
We follow DiskANN's official evaluation and use two publicly available datasets.
We vary the search parameter L to evaluate the recall–throughput trade-off of PathSeer and existing filtered search methods. For each query, we precompute an allow_ids bit vector and extend diskann-benchmark to accept these bit vectors. The reported throughput measures in-memory vector search only, excluding the preprocessing time for constructing filter bit vectors. All experiments use Top-k = 10, consistent with the official benchmark.
Experimental results
The results demonstrate that PathSeer consistently achieves comparable or better performance than existing methods. Compared with the best-performing baseline for each workload, PathSeer achieves 1.11–2.18× throughput (1.46× on average) at a target recall of 0.90 and 1.12–2.15× throughput (1.42× on average) at a target recall of 0.95.