Skip to content

eliminate the effect of data size on the efsearch threshold#993

Merged
inabao merged 1 commit into
mainfrom
datasize-efsearch
Aug 1, 2025
Merged

eliminate the effect of data size on the efsearch threshold#993
inabao merged 1 commit into
mainfrom
datasize-efsearch

Conversation

@inabao

@inabao inabao commented Jul 30, 2025

Copy link
Copy Markdown
Collaborator

Summary by Sourcery

Enforce a consistent ef_search threshold across graph and HNSW searches and consolidate parameter parsing to eliminate code duplication and the impact of data size on the threshold.

Enhancements:

  • Unify ef_search threshold logic in HGraph and HNSW to use max(AMPLIFICATION_FACTOR * k, 1000) for range validation
  • Consolidate parameter parsing and ef_search validation into a single location in each search overload to remove duplicate code
  • Reorder validations to perform ef_search range checks before k constraints and locking operations

Signed-off-by: jinjiabao.jjb <jinjiabao.jjb@antgroup.com>
@inabao inabao self-assigned this Jul 30, 2025
@inabao inabao added the version/0.16 1. Add SINDI 2. Extend HGraph 1. 新增SINDI 2. 扩展 HGraph label Jul 30, 2025
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Important

Installation incomplete: to start using Gemini Code Assist, please ask the organization owner(s) to visit the Gemini Code Assist Admin Console and sign the Terms of Services.

@sourcery-ai

sourcery-ai Bot commented Jul 30, 2025

Copy link
Copy Markdown

Reviewer's Guide

This PR refactors the search methods to enforce the ef_search threshold consistently at the start of each KnnSearch call—using max(AMPLIFICATION_FACTOR * k, 1000)—removes duplicated threshold checks in HGraph, and aligns the k validation and lock ordering in HNSW::knn_search to match the new pattern.

Sequence diagram for consistent ef_search threshold validation in KnnSearch

sequenceDiagram
    participant User
    participant HGraph
    participant HGraphSearchParameters
    User->>HGraph: KnnSearch(query, k, parameters, filter)
    HGraph->>HGraphSearchParameters: FromJson(parameters)
    HGraph->>HGraph: Compute ef_search_threshold = max(AMPLIFICATION_FACTOR * k, 1000)
    HGraph->>HGraph: CHECK_ARGUMENT(1 <= params.ef_search <= ef_search_threshold)
    HGraph->>HGraph: CHECK_ARGUMENT(k > 0)
    HGraph->>HGraph: k = min(k, GetNumElements())
    Note right of HGraph: Proceed with search logic
Loading

Sequence diagram for reordered validation and locking in HNSW::knn_search

sequenceDiagram
    participant User
    participant HNSW
    participant HnswSearchParameters
    User->>HNSW: knn_search(query, k, parameters, ...)
    HNSW->>HnswSearchParameters: FromJson(parameters)
    HNSW->>HNSW: Compute ef_search_threshold = max(AMPLIFICATION_FACTOR * k, 1000)
    HNSW->>HNSW: CHECK_ARGUMENT(1 <= params.ef_search <= ef_search_threshold)
    HNSW->>HNSW: CHECK_ARGUMENT(k > 0)
    HNSW->>HNSW: k = min(k, GetNumElements())
    HNSW->>HNSW: std::shared_lock lock_global(rw_mutex_)
    Note right of HNSW: Continue with search logic
Loading

File-Level Changes

Change Details Files
Refactor HGraph::KnnSearch to apply ef_search threshold early
  • Inserted parameter parsing and ef_search range check at the top of both overloads
  • Removed redundant FromJson and threshold validation blocks later in each function
src/algorithm/hgraph.cpp
Reorder k validation and locking in HNSW::knn_search
  • Moved k > 0 check and bounds clamp after the ef_search threshold check
  • Shifted std::shared_lock acquisition to follow parameter validation
src/index/hnsw.cpp

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@inabao

inabao commented Jul 30, 2025

Copy link
Copy Markdown
Collaborator Author

@sourcery-ai summary

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey @inabao - I've reviewed your changes - here's some feedback:

  • The repeated ef_search threshold calculation and validation across multiple overloads should be refactored into a shared helper to reduce duplication and ensure consistency.
  • Consider validating and capping k before computing ef_search_threshold so the threshold logic always uses the final k value.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The repeated ef_search threshold calculation and validation across multiple overloads should be refactored into a shared helper to reduce duplication and ensure consistency.
- Consider validating and capping k before computing ef_search_threshold so the threshold logic always uses the final k value.

## Individual Comments

### Comment 1
<location> `src/algorithm/hgraph.cpp:303` </location>
<code_context>
+
+    auto params = HGraphSearchParameters::FromJson(parameters);
+
+    auto ef_search_threshold = std::max(AMPLIFICATION_FACTOR * k, 1000L);
+    CHECK_ARGUMENT(  // NOLINT
+        (1 <= params.ef_search) and (params.ef_search <= ef_search_threshold),
+        fmt::format("ef_search({}) must in range[1, {}]", params.ef_search, ef_search_threshold));
</code_context>

<issue_to_address>
The ef_search_threshold calculation uses k before it is clamped to the number of elements.

Since k is clamped after ef_search_threshold is calculated, ef_search_threshold may be set too high if k exceeds the dataset size. Consider basing ef_search_threshold on the clamped k value for more accurate validation.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
    auto ef_search_threshold = std::max(AMPLIFICATION_FACTOR * k, 1000L);
    CHECK_ARGUMENT(  // NOLINT
        (1 <= params.ef_search) and (params.ef_search <= ef_search_threshold),
        fmt::format("ef_search({}) must in range[1, {}]", params.ef_search, ef_search_threshold));

    // check k
    CHECK_ARGUMENT(k > 0, fmt::format("k({}) must be greater than 0", k));
    k = std::min(k, GetNumElements());
=======
    // check k
    CHECK_ARGUMENT(k > 0, fmt::format("k({}) must be greater than 0", k));
    k = std::min(k, GetNumElements());

    auto ef_search_threshold = std::max(AMPLIFICATION_FACTOR * k, 1000L);
    CHECK_ARGUMENT(  // NOLINT
        (1 <= params.ef_search) and (params.ef_search <= ef_search_threshold),
        fmt::format("ef_search({}) must in range[1, {}]", params.ef_search, ef_search_threshold));
>>>>>>> REPLACE

</suggested_fix>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/algorithm/hgraph.cpp
Comment on lines +303 to 310
auto ef_search_threshold = std::max(AMPLIFICATION_FACTOR * k, 1000L);
CHECK_ARGUMENT( // NOLINT
(1 <= params.ef_search) and (params.ef_search <= ef_search_threshold),
fmt::format("ef_search({}) must in range[1, {}]", params.ef_search, ef_search_threshold));

// check k
CHECK_ARGUMENT(k > 0, fmt::format("k({}) must be greater than 0", k));
k = std::min(k, GetNumElements());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion (bug_risk): The ef_search_threshold calculation uses k before it is clamped to the number of elements.

Since k is clamped after ef_search_threshold is calculated, ef_search_threshold may be set too high if k exceeds the dataset size. Consider basing ef_search_threshold on the clamped k value for more accurate validation.

Suggested change
auto ef_search_threshold = std::max(AMPLIFICATION_FACTOR * k, 1000L);
CHECK_ARGUMENT( // NOLINT
(1 <= params.ef_search) and (params.ef_search <= ef_search_threshold),
fmt::format("ef_search({}) must in range[1, {}]", params.ef_search, ef_search_threshold));
// check k
CHECK_ARGUMENT(k > 0, fmt::format("k({}) must be greater than 0", k));
k = std::min(k, GetNumElements());
// check k
CHECK_ARGUMENT(k > 0, fmt::format("k({}) must be greater than 0", k));
k = std::min(k, GetNumElements());
auto ef_search_threshold = std::max(AMPLIFICATION_FACTOR * k, 1000L);
CHECK_ARGUMENT( // NOLINT
(1 <= params.ef_search) and (params.ef_search <= ef_search_threshold),
fmt::format("ef_search({}) must in range[1, {}]", params.ef_search, ef_search_threshold));

@codecov

codecov Bot commented Jul 31, 2025

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

@@            Coverage Diff             @@
##             main     #993      +/-   ##
==========================================
- Coverage   91.92%   91.69%   -0.23%     
==========================================
  Files         293      293              
  Lines       17020    17022       +2     
==========================================
- Hits        15645    15609      -36     
- Misses       1375     1413      +38     
Flag Coverage Δ
cpp 91.69% <100.00%> (-0.23%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
common 92.51% <ø> (ø)
datacell 91.44% <ø> (-0.52%) ⬇️
index 90.56% <100.00%> (-0.15%) ⬇️
simd 100.00% <ø> (ø)

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update cd9d9e9...f740381. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@inabao inabao added the kind/improvement Optimizations, UX polish, or minor improvements 性能优化、体验打磨或细节改良 label Jul 31, 2025
Comment thread src/algorithm/hgraph.cpp
(1 <= params.ef_search) and (params.ef_search <= ef_search_threshold),
fmt::format("ef_search({}) must in range[1, {}]", params.ef_search, ef_search_threshold));

// check k

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

what will happen, when ef_search larger than num_element?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The function will return all vectors if the graph is connected; otherwise, it will return a connected component.

@LHT129 LHT129 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

@wxyucs wxyucs left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

lgtm

@inabao
inabao merged commit 5657cb1 into main Aug 1, 2025
23 of 26 checks passed
@inabao
inabao deleted the datasize-efsearch branch August 1, 2025 07:04
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Important

Installation incomplete: to start using Gemini Code Assist, please ask the organization owner(s) to visit the Gemini Code Assist Admin Console and sign the Terms of Services.

LHT129 pushed a commit to LHT129/vsag that referenced this pull request Apr 16, 2026
…#993)

Signed-off-by: jinjiabao.jjb <jinjiabao.jjb@antgroup.com>
LHT129 pushed a commit that referenced this pull request May 11, 2026
Signed-off-by: jinjiabao.jjb <jinjiabao.jjb@antgroup.com>
Signed-off-by: LHT129 <tianlan.lht@antgroup.com>
Sia-Sheerland pushed a commit to Sia-Sheerland/vsag that referenced this pull request Jun 26, 2026
…#993)

Signed-off-by: jinjiabao.jjb <jinjiabao.jjb@antgroup.com>
Signed-off-by: Sia Sheerland <x1075956441x@163.com>

Signed-off-by: Sia Sheerland <x1075956441x@163.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/improvement Optimizations, UX polish, or minor improvements 性能优化、体验打磨或细节改良 size/M version/0.16 1. Add SINDI 2. Extend HGraph 1. 新增SINDI 2. 扩展 HGraph

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants