eliminate the effect of data size on the efsearch threshold#993
Conversation
Signed-off-by: jinjiabao.jjb <jinjiabao.jjb@antgroup.com>
|
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. |
Reviewer's GuideThis 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 KnnSearchsequenceDiagram
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
Sequence diagram for reordered validation and locking in HNSW::knn_searchsequenceDiagram
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
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
@sourcery-ai summary |
There was a problem hiding this comment.
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>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| 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()); |
There was a problem hiding this comment.
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.
| 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 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
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
| (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 |
There was a problem hiding this comment.
what will happen, when ef_search larger than num_element?
There was a problem hiding this comment.
The function will return all vectors if the graph is connected; otherwise, it will return a connected component.
|
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. |
…#993) Signed-off-by: jinjiabao.jjb <jinjiabao.jjb@antgroup.com>
Signed-off-by: jinjiabao.jjb <jinjiabao.jjb@antgroup.com> Signed-off-by: LHT129 <tianlan.lht@antgroup.com>
…#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>
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: