Skip to content

feat: support custom batch query distances - #2551

Merged
LHT129 merged 1 commit into
antgroup:mainfrom
LHT129:2026-07-28-为-SearchRequest-支持请求级自定义批量检索距离函数
Aug 3, 2026

Hidden character warning

The head ref may contain hidden characters: "2026-07-28-\u4e3a-SearchRequest-\u652f\u6301\u8bf7\u6c42\u7ea7\u81ea\u5b9a\u4e49\u6279\u91cf\u68c0\u7d22\u8ddd\u79bb\u51fd\u6570"
Merged

feat: support custom batch query distances#2551
LHT129 merged 1 commit into
antgroup:mainfrom
LHT129:2026-07-28-为-SearchRequest-支持请求级自定义批量检索距离函数

Conversation

@LHT129

@LHT129 LHT129 commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add a request-scoped batch callback that scores stable external IDs
  • use callback scores throughout BruteForce and HGraph KNN search
  • support IVF hybrid callback search: built-in metric routes buckets and the callback ranks their candidates
  • preserve built-in metrics for index construction

Validation

  • release build passed
  • formatting and diff checks passed
  • functional test build could not start because the environment could not download Boost; no retry was requested

Closes #2550

@LHT129
LHT129 requested a review from wxyucs as a code owner July 28, 2026 04:28
@LHT129 LHT129 added the kind/feature Brand-new functionality or capabilities 引入全新的功能、新特性或新能力 label Jul 28, 2026
@LHT129
LHT129 requested a review from inabao as a code owner July 28, 2026 04:28
@LHT129
LHT129 requested a review from jiaweizone as a code owner July 28, 2026 04:28
@LHT129 LHT129 added kind/feature Brand-new functionality or capabilities 引入全新的功能、新特性或新能力 version/1.2 labels Jul 28, 2026
@vsag-bot

vsag-bot commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

/label status/waiting-for-review
/waiting-on reviewer
/request-review @jiaweizone
/request-review @inabao

@vsag-bot
vsag-bot self-requested a review July 28, 2026 04:28
@vsag-bot

vsag-bot commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Automated pull request review completed.

Review effort: high (862 changed lines across 12 files).

Submitted 2 inline comments.
Review: #2551 (review)

@mergify

mergify Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Merge Protections

🟢 All 3 merge protections satisfied — ready to merge.

Show 3 satisfied protections

🟢 Require kind label

  • label~=^kind/

🟢 Require version label

  • label~=^version/

🟢 Require linked issue for feature/bug PRs

  • body~=(?im)(?:^|[\s\-\*])(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s*:?\s+(?:#\d+|[\w.\-]+/[\w.\-]+#\d+|https?://github\.com/[\w.\-]+/[\w.\-]+/issues/\d+)

@vsag-bot vsag-bot 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.

Automated inline review completed.

Review effort: medium (310 changed lines across 8 files).
Submitted 4 inline comments.

Reviewed commit ca17c0d.

Comment thread src/impl/searcher/basic_searcher.cpp Outdated
Comment thread src/impl/searcher/basic_searcher.cpp
Comment thread src/algorithm/bruteforce/bruteforce.cpp Outdated
Comment thread src/impl/searcher/basic_searcher.cpp Outdated
Comment thread tests/test_hgraph.cpp
Comment thread include/vsag/search_request.h

@LHT129 LHT129 left a comment

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.

Overall this is a well-structured PR that adds request-scoped custom distance callbacks to BruteForce and HGraph, with clean rejection in IVF. The implementation correctly disables features that depend on vector-space semantics (reorder, rabitq, brute-force threshold fallback, duplicate-finding) and forces single-threaded execution when the callback is active.

A few areas worth addressing before merge:

  1. HGraph entry-point filtering (basic_searcher.cpp:441): When the entry point is rejected by the filter, the search returns empty immediately instead of traversing through it. Normal HGraph search scores and traverses a rejected entry point; the custom path should do the same.

  2. Duplicate external IDs (basic_searcher.cpp:520): When consider_duplicate is true, duplicate IDs are pushed with the representative's callback score without invoking the callback for each duplicate. Since custom scores are per external ID, this can produce wrong distances.

  3. Per-batch label allocation (basic_searcher.cpp:427): score_ids constructs a Vector<int64_t> per callback batch inside the graph expansion hot loop. With the default distance_batch_size_ of 1, this is one allocation per scored neighbor. A pre-allocated buffer would avoid this.

  4. Scalar validation (bruteforce.cpp:385): Skipping validate_knn_args / validate_range_args entirely also skips checks for topk_ == 0, limited_size_ == 0, and negative radii — all of which are independent of the query vector. These should still be validated.

  5. Missing HGraph error-path tests: BruteForce has validation tests for distance_batch_size_ == 0 and non-finite scores; HGraph should have equivalent coverage, plus a test for the range-search rejection path.

@LHT129
LHT129 force-pushed the 2026-07-28-为-SearchRequest-支持请求级自定义批量检索距离函数 branch from ca17c0d to fac0f30 Compare July 28, 2026 06:30
@vsag-bot
vsag-bot self-requested a review July 28, 2026 06:30

@vsag-bot vsag-bot 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.

Automated inline review completed.

Review effort: medium (361 changed lines across 8 files).
Submitted 3 inline comments.

Reviewed commit fac0f30.

Comment thread src/algorithm/bruteforce/bruteforce.cpp Outdated
Comment thread src/impl/searcher/basic_searcher.cpp
Comment thread include/vsag/search_request.h

@LHT129 LHT129 left a comment

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.

All previously reported issues have been addressed in this commit:

  • [P2] Scalar search-argument validation: BruteForce now independently validates topk_, radius_, and limited_size_ for custom distance callbacks instead of skipping the entire validator.
  • [P2] Preserve traversal when entry point is filtered: basic_searcher.cpp now scores the entry point via score_ids and lets check_func control result admission, preserving graph connectivity.
  • [P2] Score duplicate external IDs independently: Duplicate IDs now invoke score_ids individually in the custom distance path.
  • [P2] Avoid per-batch label vector allocation: custom_labels is now pre-allocated once per search and reused across score_ids invocations.
  • [suggestion] HGraph error-path tests: Validation tests for distance_batch_size_ == 0, non-finite scores, and range search rejection are now present.

No new issues found. The implementation correctly handles parameter validation, graph traversal, batching, and duplicate IDs across BruteForce and HGraph. IVF correctly rejects the callback with a clear error.

@LHT129
LHT129 force-pushed the 2026-07-28-为-SearchRequest-支持请求级自定义批量检索距离函数 branch from fac0f30 to 991a6c8 Compare July 28, 2026 07:10
@vsag-bot
vsag-bot self-requested a review July 28, 2026 07:10
@mergify mergify Bot added the module/docs label Jul 28, 2026

@vsag-bot vsag-bot 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.

Automated inline review completed.

Review effort: medium (437 changed lines across 10 files).
Submitted 2 inline comments.

Reviewed commit 991a6c8.

Comment thread src/algorithm/bruteforce/bruteforce.cpp Outdated
Comment thread src/algorithm/ivf/ivf.cpp Outdated
Comment thread src/impl/searcher/basic_searcher.cpp
Comment thread src/algorithm/ivf/ivf.cpp Outdated

@vsag-bot vsag-bot 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.

Automated inline review completed.

Review effort: high (573 changed lines across 10 files).
Submitted 3 inline comments.

Reviewed commit 4f8f691.

Comment thread src/algorithm/hgraph/hgraph_search.cpp
Comment thread src/algorithm/hgraph/hgraph_search.cpp Outdated
Comment thread src/impl/searcher/basic_searcher.cpp Outdated
@LHT129
LHT129 force-pushed the 2026-07-28-为-SearchRequest-支持请求级自定义批量检索距离函数 branch from 4f8f691 to 67b945b Compare July 31, 2026 07:24
Comment thread src/algorithm/ivf/ivf.cpp
@LHT129
LHT129 force-pushed the 2026-07-28-为-SearchRequest-支持请求级自定义批量检索距离函数 branch from 67b945b to 17dd323 Compare July 31, 2026 07:35
@vsag-bot
vsag-bot self-requested a review July 31, 2026 07:35
Comment thread tests/test_ivf.cpp
Comment thread tests/test_ivf.cpp

@vsag-bot vsag-bot 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.

Automated inline review completed.

Review effort: high (810 changed lines across 12 files).
Submitted 5 inline comments.

Reviewed commit 17dd323.

Comment thread tests/test_hgraph.cpp Outdated
Comment thread src/algorithm/ivf/ivf.cpp
Comment thread src/algorithm/ivf/ivf.cpp Outdated
Comment thread src/algorithm/ivf/ivf.cpp
Comment thread src/algorithm/ivf/ivf.cpp
@LHT129
LHT129 force-pushed the 2026-07-28-为-SearchRequest-支持请求级自定义批量检索距离函数 branch from 17dd323 to 63b6e11 Compare August 3, 2026 03:18
Copilot AI review requested due to automatic review settings August 3, 2026 03:18
@vsag-bot
vsag-bot self-requested a review August 3, 2026 03:18

Copilot AI left a comment

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.

🟡 Not ready to approve

The implementation adds IVF callback support but the linked issue/PR description state IVF should reject callbacks, so the intended behavior/scope needs to be reconciled before approval.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Pull request overview

Adds a request-scoped, batched “custom distance” callback to SearchRequest and threads it through search execution so callers can score candidates by stable external IDs at query time (runtime-only, index metric for build remains unchanged).

Changes:

  • Introduces SearchDistanceBatchFunc + distance_batch_size_ on vsag::SearchRequest and plumbs them into inner search parameters.
  • Implements callback-driven scoring in BruteForce and HGraph KNN traversal (including validation and duplicate-handling adjustments).
  • Adds IVF callback search path (plus validation), updates API docs (EN/ZH), and adds functional tests for BruteForce/HGraph/IVF callback behavior and invalid configurations.
File summaries
File Description
tests/test_ivf.cpp Adds coverage for IVF callback KNN plus rejected modes/configs.
tests/test_hgraph.cpp Adds coverage for HGraph callback KNN plus validation failures.
tests/test_brute_force.cpp Adds callback KNN/range + validation coverage; includes batching assertions.
src/impl/searcher/basic_searcher.cpp Enables callback scoring path inside graph traversal when distance_batch_func is set.
src/impl/inner_search_param.h Carries callback + batch size into inner search params.
src/algorithm/ivf/ivf.h Declares a custom-distance IVF search helper.
src/algorithm/ivf/ivf.cpp Implements callback-driven IVF candidate scoring + request validation gate.
src/algorithm/hgraph/hgraph_search.cpp Validates/rejects unsupported options in callback mode; routes traversal to callback scoring.
src/algorithm/bruteforce/bruteforce.cpp Adds callback scoring path with batching; improves exception handling for parallel futures.
include/vsag/search_request.h Public API: adds callback type + fields and documents behavior.
docs/docs/en/src/api/search.md Documents callback semantics and per-index support/constraints (EN).
docs/docs/zh/src/api/search.md Documents callback semantics and per-index support/constraints (ZH).
Review details
  • Files reviewed: 12/12 changed files
  • Comments generated: 3
  • Review effort level: Lite

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

Comment thread src/algorithm/ivf/ivf.cpp
Comment thread docs/docs/en/src/api/search.md Outdated
Comment thread docs/docs/zh/src/api/search.md Outdated

@vsag-bot vsag-bot 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.

Automated inline review completed.

Review effort: high (855 changed lines across 12 files).
Submitted 1 inline comment.

Reviewed commit 63b6e11.

Comment thread src/algorithm/hgraph/hgraph_search.cpp

@LHT129 LHT129 left a comment

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.

This iteration addresses all previously raised issues:

  • Entry-point filtering (P2): Entry point is now scored via score_ids before the filter check, preserving graph traversal connectivity.
  • Duplicate scoring (P2): The score_duplicates lambda scores each eligible duplicate independently through the callback, with proper batching and overflow protection.
  • Scalar validation (P2): topk, radius, and limited_size are now independently validated for custom-distance requests, preventing OOB access on zero-capacity heaps.
  • Label buffer allocation (P2): custom_labels is now a pre-allocated Vector bounded by min(distance_batch_size, graph->MaximumDegree()), eliminating per-batch allocations in the hot loop.
  • Reasoning output (P3): HGraph custom callback searches now retain expected-label reasoning with true distances obtained through the callback.
  • Duplicate stat counting (P3): dist_cmp is incremented for callback-scored duplicates.
  • HGraph validation tests: Error-path tests for distance_batch_size_ == 0, non-finite scores, range search rejection, parallel search rejection, and brute_force_threshold rejection are now covered.

Additional improvements in this revision:

  • visited_list_guard RAII wrapper ensures the visited list is always returned to the pool, even on early returns.
  • BruteForce parallel search now collects exceptions from all futures before rethrowing, preventing abandoned tasks.
  • The start >= end guard in BruteForce parallel chunking avoids submitting empty work items.

No new issues found. The implementation is thorough with good test coverage across BruteForce, HGraph, and IVF.

@LHT129 LHT129 left a comment

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.

This latest revision (63b6e11) is a clean squashed version that incorporates all previously addressed fixes. After thorough review of the full diff (792 additions, 63 deletions across 12 files), no new issues were found.

Summary of what was verified:

  • Public API (search_request.h): Clean addition of SearchDistanceBatchFunc type alias and two new fields with clear documentation.
  • BruteForce (bruteforce.cpp): Proper batch-distance loop with flush_custom_batch, independent scalar validation for custom mode, exception-safe parallel search with start >= end guard.
  • HGraph (hgraph_search.cpp): Entry-point scoring before filter check, score_duplicates with independent callback scoring and overflow protection, visited_list_guard RAII, disabled brute_force_threshold/parallel/reorder/rabitq for custom mode.
  • IVF (ivf.cpp): New search_with_custom_distance with proper bucket routing, batch submission, timeout handling, and multi-bucket dedup via std::unordered_map (consistent with existing IVF::search pattern).
  • BasicSearcher (basic_searcher.cpp): Pre-allocated custom_labels buffer, score_ids and score_duplicates lambdas with proper batching and stat counting, find_duplicate disabled for custom mode.
  • Tests: Comprehensive coverage across all three index types including happy path, validation errors, and unsupported configuration rejection.
  • Docs: Both English and Chinese documentation updated with clear API descriptions and per-index behavior notes.

The implementation is thorough, well-tested, and ready for merge.

Signed-off-by: LHT129 <tianlan.lht@antgroup.com>
Co-authored-by: opencode <opencode@anthropic.com>
Copilot AI review requested due to automatic review settings August 3, 2026 06:23
@LHT129
LHT129 force-pushed the 2026-07-28-为-SearchRequest-支持请求级自定义批量检索距离函数 branch from 63b6e11 to 4c2952d Compare August 3, 2026 06:23
@vsag-bot
vsag-bot self-requested a review August 3, 2026 06:23
Comment thread src/algorithm/ivf/ivf.cpp

Copilot AI left a comment

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.

🟡 Not ready to approve

IVF callback mode returns before reasoning is initialized/attached, so expected_labels_ is ignored and callback searches don’t emit reasoning traces.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Review details

Suppressed comments (1)

src/algorithm/ivf/ivf.cpp:1977

  • In IVF callback mode, the function returns early before creating/attaching a ReasoningContext, so expected_labels_ is silently ignored even though IVF otherwise supports reasoning. Also search_with_custom_distance(..., ReasoningContext*) is never given a non-null reasoning_ctx, so bucket selection / visits aren’t recorded for callback searches.
    if (use_custom_distance) {
        param.search_mode = KNN_SEARCH;
        param.topk = request.topk_;
        auto search_result = search_with_custom_distance(query, request, param, ctx);
        if (search_result == nullptr || search_result->Empty()) {
            auto dataset_results = DatasetImpl::MakeEmptyDataset();
            dataset_results->Statistics(stats.Dump());
            return dataset_results;
        }
        auto dataset_results = this->pack_knn_result(search_result, ctx.alloc);
        dataset_results->Statistics(stats.Dump());
        return dataset_results;
    }
  • Files reviewed: 12/12 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

Comment thread src/algorithm/ivf/ivf.cpp

@LHT129 LHT129 left a comment

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.

Overall Assessment: LGTM with minor suggestions

This PR adds support for custom batch query distance callbacks across BruteForce, HGraph, and IVF indexes. The feature is well-scoped and the implementation is clean.

What this PR does well:

  • Consistent CHECK_ARGUMENT validation across all three indexes for invalid parameter combinations
  • Proper batch scoring with configurable distance_batch_size_ to control memory/performance trade-off
  • Clear rejection of unsupported modes (range search, parallel search, etc.) with descriptive error messages
  • Good test coverage for validation paths in all three indexes
  • Documentation updates in both English and Chinese

Issues identified:

  1. [P3] std::unordered_map without allocator in IVF search_with_custom_distance — inconsistent with the rest of the function which uses allocator-aware containers
  2. [suggestion] scores.resize() vs reserve() inconsistency in IVF — reserve() would be more appropriate since the callback writes directly into scores.data()

Prior review rounds: 19 of 30 existing comments remain unresolved. The author has been iterating actively. The current diff addresses several earlier concerns (allocator usage in BruteForce, first_error propagation, visited_list_guard for HGraph).

@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

@vsag-bot vsag-bot 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.

Automated inline review completed.

Review effort: high (862 changed lines across 12 files).
Submitted 2 inline comments.

Reviewed commit 4c2952d.

Comment thread src/impl/searcher/basic_searcher.cpp
Comment thread src/algorithm/ivf/ivf.cpp
@mergify

mergify Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

@LHT129
LHT129 merged commit 137a8b9 into antgroup:main Aug 3, 2026
22 of 23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/feature Brand-new functionality or capabilities 引入全新的功能、新特性或新能力 module/api module/docs module/testing size/XL version/1.1

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support request-scoped custom batch query distances

4 participants