From b0d5929ccbb1ec4a22a0381c124f173e03c5e35c Mon Sep 17 00:00:00 2001 From: jamesgao-jpg Date: Fri, 24 Apr 2026 09:24:50 +0000 Subject: [PATCH] fix(svs_flat): accept all-clear bitset as unfiltered search Before: any non-empty BitsetView passed to SvsFlatIndexNode::Search() caused an immediate `not_implemented` return, even when every bit was zero (i.e. no vectors filtered out). Callers that pre-allocate a bitset for shape consistency -- e.g. the vecTool nightly harness always passes a bitset whose size matches the base set but leaves it all-clear for plain kNN -- would see every SVS_FLAT search fail at the first query. After: reject only when the bitset is both non-empty AND has at least one bit set. All-clear bitsets fall through to the non-bitset search path, which is the correct semantic for "no filtering requested". `BitsetView::count()` (include/knowhere/bitsetview.h:50) returns the number of filtered-out bits / ids, so the added `&& bitset.count() > 0` is cheap and doesn't scan the bitmap. Also register raw `SVS_VAMANA` in the SVS registration block so the factory can construct it, matching the existing `Type()` implementation and the LVQ / LeanVec registrations in the same file. No regression on the actual-filter case: when the caller does have bits set, we still surface the same not_implemented error with the same message string, matching the current behavior. Fixes one of the class of failures seen when running the vecTool newNightly L2 SVS smoke benchmark (all 6 SVS_FLAT groups across cohere_1m + qwen3vl_200k x {fp32, fp16, bf16} previously failed identically at search stage; HNSW siblings on the same group IDs passed). See zilliztech/vecTool#21 for the upstream discussion. Signed-off-by: jamesgao-jpg --- src/index/svs/svs_flat.cc | 2 +- src/index/svs/svs_vamana.cc | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/index/svs/svs_flat.cc b/src/index/svs/svs_flat.cc index 0101586a7..a80f3fdac 100644 --- a/src/index/svs/svs_flat.cc +++ b/src/index/svs/svs_flat.cc @@ -76,7 +76,7 @@ class SvsFlatIndexNode : public IndexNode { return expected::Err(Status::empty_index, "index not loaded"); } - if (!bitset.empty()) { + if (!bitset.empty() && bitset.count() > 0) { return expected::Err(Status::not_implemented, "SVS Flat does not support bitset filtering"); } diff --git a/src/index/svs/svs_vamana.cc b/src/index/svs/svs_vamana.cc index 88fd0f60f..e1e93eb72 100644 --- a/src/index/svs/svs_vamana.cc +++ b/src/index/svs/svs_vamana.cc @@ -519,6 +519,8 @@ class SvsVamanaLeanVecIndexNode : public SvsVamanaIndexNode { // temporarily removed `MMAP` until it's fully honored by SVS +KNOWHERE_MOCK_REGISTER_DENSE_FLOAT_ALL_GLOBAL(SVS_VAMANA, SvsVamanaIndexNode, knowhere::feature::NONE) + KNOWHERE_MOCK_REGISTER_DENSE_FLOAT_ALL_GLOBAL(SVS_VAMANA_LVQ, SvsVamanaLvqIndexNode, knowhere::feature::NONE) KNOWHERE_MOCK_REGISTER_DENSE_FLOAT_ALL_GLOBAL(SVS_VAMANA_LEANVEC, SvsVamanaLeanVecIndexNode, knowhere::feature::NONE)