Return native indexed vectors from disk search - #1345
Conversation
There was a problem hiding this comment.
Pull request overview
This PR extends diskann-disk’s disk-index search surface with a new API that returns only valid ANN hits, each bundled with its canonical (native) indexed vector as stored in the on-disk graph. This supports downstream consumers that need full-precision indexed vectors alongside IDs/distances, while keeping the existing search() API unchanged.
Changes:
- Added
search_with_indexed_vectors(...)plus new result types to return owned per-hit indexed vectors without padding. - Implemented request-local indexed-vector capture via an
IndexedVectorCollector, with different capture strategies per search mode and a post-rerank “missing winner” batch fetch. - Expanded tests (including builder tests) to validate result parity, ownership/capacity behavior, and stored-vector round-trip behavior (including MinMax).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| diskann-disk/src/search/provider/disk_provider.rs | Adds the new public search API, request-local vector collector, capture logic across traversal/post-processing, and associated tests. |
| diskann-disk/src/build/builder/tests.rs | Extends disk index build tests to validate returned indexed vectors against stored rows. |
| diskann-disk/src/build/builder/core.rs | Adds a test helper that verifies indexed vectors returned by search match the stored dataset rows. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1345 +/- ##
==========================================
- Coverage 91.58% 91.55% -0.03%
==========================================
Files 521 521
Lines 99598 100347 +749
==========================================
+ Hits 91212 91874 +662
- Misses 8386 8473 +87
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
|
The API and its intended behavior make sense, but I’m concerned about the complexity and performance cost of the collector design.
I also think the |
2e63be2 to
faf5b0b
Compare
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
faf5b0b to
4efb698
Compare
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Thanks Yujie, I have left some comments but they can mostly come in follow-up since I know this is time sensitive. I am approving but would be good to beef-up the testing a bit before merging. From what I can tell there is only one test with a single query testing this new path. Would also be good to test the error cases.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Adds an opt-in disk search API that returns each valid ANN result with its canonical native indexed vector:
The existing
search()API and its padded result behavior remain unchanged.Public contract
results.len() == stats.result_count.ANNError, not a panic.For reviewers
Recommended review order:
SearchResultWithIndexedVectors,SearchResultItemWithIndexedVector, andsearch_with_indexed_vectors.SearchPayloadandSearchOutputextend the existing slice-backed output without changing legacysearch().DiskAccessor::ensure_loadedoptionally stores the native vector beside the existing exact-distance cache entry.extend_outputmoves traversal-cached winner vectors into results or copies winners from the post-process batch already loaded by the existing rerank path.DiskAccessor::dropimmediately releases vectors left in the request-local cache.The intended invariants are:
vertex_idas its result.search()does not allocate or copy indexed vectors.Key data structures
Internal search payload
The
Optionis internal: legacy search writesNone; indexed-vector search writesSome(vector). The public indexed-vector result contains a non-optionalBox<[V]>.Output adapter
SearchOutputkeeps the existing ID/distance/associated-data buffers and adds an optional vector lane. Onepushwrites all fields at the same position, preserving ID/vector alignment without replacing the existing search pipeline.Request-local traversal cache
The map already existed for exact distance and associated data. When indexed vectors are requested, the same entry also owns the native vector loaded during traversal. There is no collector, mutex, or second hash map. The map is cleared when the query accessor is dropped so loser vectors are not retained in the scratch pool between requests.
Data flow
extend_outputnever callsload_vertices, so it does not introduce a final fallback I/O pass.Benchmark
GitHub Actions run with immediate cleanup, using K=1000, L=2000, recall@100, and four search threads:
Expected Peak-Memory Increase
The indexed-vector API retains the full-precision vectors needed by active searches. Its expected vector-payload increase can therefore be approximated as:
Expected peak delta ≈ C × L × D × S
where:
For Wikipedia-100K:
4 × 2000 × 768 × 4 bytes ≈ 23.44 MiB
This closely matches the measured increase of 23.25 MiB.
Closes #1339