Skip to content

Add algorithm and benchmark for filtered range search - #1228

Open
Magdalen Dobson Manohar (magdalendobson) wants to merge 68 commits into
mainfrom
users/magdalen/range_filter
Open

Add algorithm and benchmark for filtered range search#1228
Magdalen Dobson Manohar (magdalendobson) wants to merge 68 commits into
mainfrom
users/magdalen/range_filter

Conversation

@magdalendobson

@magdalendobson Magdalen Dobson Manohar (magdalendobson) commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

This PR adds an algorithm for filtered range search to the DiskANN repository. Details of the algorithm, along with the experiments supporting it, are at this Wiki page.

This PR:

  1. Adds the new algorithm to diskann, along with integration tests.
  2. Adds the new algorithm as an option in diskann-benchmark, along with an integration test.
  3. Adds filtered range groundtruth files in test_data.

Some enhancements/fixes to range search along the way:

  1. Added range groundtruth in test_data for yfcc.
  2. Fixed a bug where range search was not always honoring the maximum number of returned results.
  3. Added integration tests for range search making sure a set maximum number of results is actually respected.

Magdalen Manohar and others added 30 commits May 14, 2026 17:56
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Magdalen Dobson Manohar (magdalendobson) added a commit that referenced this pull request Jul 14, 2026
While working on #1228, I noticed that there were some issues with our
current implementation of range search and its testing.

The main issue with testing is that there were no tests ensuring the
`max_results` parameter was respected. I have added two tests that
ensure this now.

The main code had several issues with how `max_results` was handled:
1. The `max_results` parameter was allowed to be less than the initial
L_search. This is a conceptual issue because the user expects
`max_results` to stop the search from continuing for too long, and the
compute used in the initial search will always be controlled by
`initial_search_l`.
2. A `max_results` check was not enforced before deciding to continue to
the second round search. This meant that if the max results was reached
via the initial search, it might not be respected.
3. The second round search was not terminated when `max_results` was
reached, meaning it would continue to perform unnecessary work.

This PR fixes these issues by adding additional checks of `max_results`
at the correct points in the code.

---------

Co-authored-by: Magdalen Manohar <mmanohar@microsoft.com>
Magdalen Manohar added 2 commits July 16, 2026 16:06
weiyaoluo (SeliMeli) pushed a commit to SeliMeli/DiskANN that referenced this pull request Jul 22, 2026
While working on microsoft#1228, I noticed that there were some issues with our
current implementation of range search and its testing.

The main issue with testing is that there were no tests ensuring the
`max_results` parameter was respected. I have added two tests that
ensure this now.

The main code had several issues with how `max_results` was handled:
1. The `max_results` parameter was allowed to be less than the initial
L_search. This is a conceptual issue because the user expects
`max_results` to stop the search from continuing for too long, and the
compute used in the initial search will always be controlled by
`initial_search_l`.
2. A `max_results` check was not enforced before deciding to continue to
the second round search. This meant that if the max results was reached
via the initial search, it might not be respected.
3. The second round search was not terminated when `max_results` was
reached, meaning it would continue to perform unnecessary work.

This PR fixes these issues by adding additional checks of `max_results`
at the correct points in the code.

---------

Co-authored-by: Magdalen Manohar <mmanohar@microsoft.com>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Magdalen, appreciate the work on this iteration!

Comment thread diskann/src/graph/test/cases/range_search.rs
Comment thread diskann/src/graph/test/cases/range_search.rs
Comment thread diskann/src/graph/search/range_search.rs Outdated
Comment thread diskann/src/graph/search/range_search.rs
Comment thread diskann/src/graph/search/inline_filter_search.rs
Comment thread diskann/src/graph/search/filtered_range_search.rs Outdated
Comment thread diskann/src/graph/search/filtered_range_search.rs Outdated
Comment thread diskann/src/graph/search/filtered_range_search.rs
Comment thread diskann-benchmark-core/src/search/graph/filtered_range.rs Outdated
Comment thread diskann-benchmark/src/index/inmem/spherical.rs
Comment thread diskann/src/graph/search/filtered_range_search.rs Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Magdalen, just a few small comments. After this PR lands, need a serious garbage collection pass on algorithm implementations. The sharing of scratch space and general code organization has reached a point where we need to reevaluate the design. This reevaluation is not actionable for this PR.

beam_width: Option<usize>,
starting_l: NonZeroUsize,
/// Beam width.
beam_width: NonZeroUsize,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing for the larger range search cleanup: it would be nice to have a central summary of what all these parameters are expected to do algorithmically.

// using an always-true filter, because the filtered //
// initial search returns every predicate-satisfying //
// point it finds as opposed to only those in //
// `scratch.best`. //

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please avoid referring to specific variable names when describing behavior. If the variable name changes, this will go out of date.

let description = "Test of `max_results` that sets `initial_l_search` \
below `max_results` so that a second round of search is triggered. Note that \
the result set size is expected to be below `max_results` due to filtering \
out start points during `post_process`.";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we increase the internal max_results in case start points are filtered?

/// a reviewer may need to either understand why this test is checked in or to validate
/// any changes that occur in the checked-in file.
pub(super) description: String,
pub(super) grid_size: usize,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we include grid_dim as well?


InternalSearchStats {
cmps: cmps + range_stats.cmps,
hops: hops + range_stats.hops,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there some double counting? As far as I can tell, there is no reset of the variables in scratch, so they contain history from the first call to inline_filter_search_internal.

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.

Support filtered range search

5 participants