Skip to content

Filtered search: single min-heap for the next node to visit (experiment) - #455

Closed
yuejiaointel wants to merge 6 commits into
mainfrom
feature/filtered-search-min-heap
Closed

yuejiaointel wants to merge 6 commits into
mainfrom
feature/filtered-search-min-heap

Conversation

@yuejiaointel

Copy link
Copy Markdown
Contributor

Built on top of #442 (the branch includes its commits). Only the last commit is new here.

Idea

Experiment: in filtered dynamic search, take the next node to visit from a single min-heap (closest entry on top) instead of the sorted list. The sorted list then only keeps the best valid entries (the results), so it stays at most the buffer capacity long.

  • Insert: push to the min-heap (O(log n)); if the node passes, also insert it into the short sorted list of results.
  • Next node to visit: pop the min-heap top (no scan).
  • Stop: the heap is empty, or the results are full and the heap top is worse than the worst result.
  • Duplicate check: a hash set of ids queued in this search.
  • cleanup() clears the heap; the results are already sorted and valid (top-up, copy-out unchanged).

Changes

  • MutableBuffer (dynamic_search_buffer.h), opt-in via enable_heap(): insert / push_back / next / done / sort / cleanup use the heap while searching.
  • MutableVamanaIndex::search turns it on only when a filter is passed. Unfiltered search, the static index, greedy_search, and the batch iterator are unchanged.
  • Limitation: treats the search window as the full capacity (no split buffer).
  • Test: MutableBuffer "Heap" section.

🤖 Generated with Claude Code

Reuse the MutableBuffer valid/invalid mechanism: a FilteredValidBuilder marks an
entry invalid if it is deleted or the predicate rejects its external id. New
MutableVamanaIndex::search overload taking a predicate, padding rows with
id -1 / +inf and returning per-query found counts. Supplement path checks the
predicate before computing the distance. Orchestrator virtual appended last.
Replace the separate filtered search overload with two optional trailing
arguments on MutableVamanaIndex::search (an id predicate and a per-query
result count). Without a predicate the existing code path runs unchanged.
check_and_supplement_search_buffer gets an optional predicate that is
checked before the distance is computed. The filter predicate type is now
a type-erased std::function, so FilteredValidBuilder is no longer a
template. The orchestrator keeps one appended virtual that forwards to the
index search.
The optional filter on MutableVamanaIndex::search now only chooses which
builder the existing greedy search closure uses; both cases call the same
per_thread_batch_search. FilteredValidBuilder derives from ValidBuilder.
The buffer top-up in single_search applies the filter when the search
closure carries one. The per-query result count out-parameter is removed
(callers count non-padding ids).

per_thread_batch_search now pads result rows with fewer than k entries
(id size_t(-1), distance +inf) instead of reading past the end of the
search buffer, and the post-search id translation skips the padding.
Give ValidBuilder an optional predicate and pass it down through
internal_search_builder, greedy_search_closure and search() as optional
arguments, instead of a separate builder and search path. Filtered-only
checks: the supplement fallback skips failing ids, copy-out pads short rows
with id -1 and the worst score, translation skips padded ids.
The orchestrator reports filtered search as unsupported for indexes whose
search has no filter argument (the concurrent index), instead of failing to
compile. In the filtered test, drop the unfiltered-padding section (padding is
filtered-only) and add an inner-product case checking padding uses -inf.
Experiment: with a filter, MutableBuffer takes the next entry to visit
from a min-heap (best on top) and keeps only the best valid entries in
its sorted list.
@yuejiaointel

Copy link
Copy Markdown
Contributor Author

Closing: experiment concluded; the work continues in #456.

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