Skip to content

fix(core): refill selective filtered top-k from exact eligible candidates - #1311

Draft
ruvnet wants to merge 4 commits into
mainfrom
fix/filtered-topk-exact-refill-1310
Draft

ruvnet wants to merge 4 commits into
mainfrom
fix/filtered-topk-exact-refill-1310

Conversation

@ruvnet

@ruvnet ruvnet commented Nov 2, 2026 •

Copy link
Copy Markdown
Owner

Purpose

Fix the visible ruvector-core::VectorDB::search post-filtering underfill path in current main. Relates to #1310.

Root cause

VectorDB::search retrieved global top-k candidates and then removed disallowed metadata matches without refilling. When the nearest global candidates were from another tenant, the answer could be empty or incomplete despite at least k eligible entries in storage. This matches the failure class documented in the Oct 24 historical comparison; it does not establish byte-for-byte identity with the older npm native package.

Change

  • Keep the unfiltered search behavior unchanged.
  • Retain the existing fast-path candidate retrieval when at least k results survive the metadata predicate.
  • When it underfills, score all matching stored vectors using the configured distance metric, sort with deterministic ID tie-break, and return the eligible top min(k, count).
  • Reject NaN/Infinity filtered queries and nonfinite stored vectors/scores during the fallback.
  • Add three tests for selective filters (including HNSW) at 1% and 10% among 1,000 vectors, exact ID/order/score/vector matching, fewer than k eligible results, and nonfinite filtered query input.

Explicit boundaries

  • This PR changes crates/ruvector-core/src/vector_db.rs, which crates/ruvector-node/src/lib.rs delegates to. It does not update independently shipped npm native binaries, ACORN, FilteredSearch helper, LlamaIndex PR fix(python): enforce LlamaIndex query restrictions and empty-field filters #1150, or duplicate-ID mutation behavior.
  • This is a correctness-first fallback, not a filtered-index performance win. It scans N storage IDs and computes distances for M eligible vectors on underfill, potentially incurring large tail latency on disk-backed or million-vector stores. Better indexed prefiltering is follow-up work under Correctness: filtered top-k underfill and vector mutation/input invariants (version-bound) #1310.
  • The source patch was inspected against main and regression tests were authored, but Rust/Cargo was not available in the current execution environment. Neither Rust tests nor hosted CI nor before/after benchmarks have been observed to pass. Do not merge until CI and performance review are complete.
  • Concurrent writes are not asserted to form an atomic snapshot of metadata and vectors. Authorization is not established by this metadata predicate.

Required validation before merge

cargo test -p ruvector-core filtered_top_k --lib
cargo test -p ruvector-core selective_hnsw --lib
cargo test -p ruvector-core --lib
cargo fmt --all -- --check
cargo clippy -p ruvector-core --all-targets -- -D warnings

Then measure filtered p50/p95/p99 at 10K, 100K and 1M vectors, 1%/10% selectivity, exact oracle and multi-tenant validity. Compare published npm binary separately after rebuilding a pinned native addon.

Acceptance: return min(k, eligible_count), unique permitted IDs, correct score/returned-vector alignment, exact ordering for fallback, and no changed unfiltered behavior.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant