perf(hgraph): optimize RaBitQ split construction#2460
Conversation
|
/label S-waiting-on-review |
Merge Protections🟢 All 2 merge protections satisfied — ready to merge. Show 2 satisfied protections🟢 Require kind label
🟢 Require version label
|
There was a problem hiding this comment.
Code Review
This pull request introduces an optimized scalar-code build path for HGraph with split RaBitQ (when fast_encode_rabitq=true). It first encodes vectors into temporary scalar codes and code sums to accelerate distance calculations during graph construction, then packs them into bit planes in parallel. The changes also add optimized SIMD kernels (AVX2, AVX512, NEON) for these operations and include comprehensive tests. The review feedback highlights a critical data race on optimized_build_code_sums_ during parallel insertions, a backward compatibility break caused by removing supplement_io_type_ serialization, and a recommendation to delete copy operations on OptimizedBuildGuard to prevent accidental copying.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
41c80c5 to
ff26979
Compare
ff26979 to
f873ff8
Compare
|
Automated pull request review completed. Review effort: Submitted 2 inline comments. |
vsag-bot
left a comment
There was a problem hiding this comment.
Automated inline review completed.
Review effort: high (2662 changed lines across 34 files).
Submitted 1 inline comment.
Reviewed commit f873ff8.
f873ff8 to
82d11ba
Compare
vsag-bot
left a comment
There was a problem hiding this comment.
Automated inline review completed.
Review effort: high (2555 changed lines across 34 files).
Submitted 1 inline comment.
Reviewed commit 82d11ba.
82d11ba to
3404d02
Compare
vsag-bot
left a comment
There was a problem hiding this comment.
Automated inline review completed.
Review effort: high (2673 changed lines across 34 files).
Submitted 1 inline comment.
Reviewed commit 3404d02.
Signed-off-by: LightWant <2510035537@qq.com> Assisted-by: Codex:gpt-5
3404d02 to
b012ae5
Compare
vsag-bot
left a comment
There was a problem hiding this comment.
Automated inline review completed.
Review effort: high (2737 changed lines across 34 files).
No actionable inline findings were found.
Reviewed commit b012ae5.
Signed-off-by: LightWant <2510035537@qq.com> Assisted-by: Codex:gpt-5
|
Updated the fast-build integration in Interface isolation
Validation
GIST1M controlled A/B (3 runs, median)
The recall delta is within normal nondeterministic graph-build variation; scalar-code query equivalence and final packed-code behavior are covered by the focused tests. No systematic build or search performance regression was observed. |
vsag-bot
left a comment
There was a problem hiding this comment.
Automated inline review completed.
Review effort: high (2968 changed lines across 36 files).
No actionable inline findings were found.
Reviewed commit faaba7a.
|
/retest |
Signed-off-by: LightWant <2510035537@qq.com> Assisted-by: Codex:gpt-5
vsag-bot
left a comment
There was a problem hiding this comment.
Automated inline review completed.
Review effort: high (2970 changed lines across 36 files).
No actionable inline findings were found.
Reviewed commit 2e49156.
Signed-off-by: LightWant <2510035537@qq.com> Assisted-by: Codex:gpt-5
Signed-off-by: LightWant <2510035537@qq.com> Assisted-by: Codex:gpt-5
vsag-bot
left a comment
There was a problem hiding this comment.
Automated inline review completed.
Review effort: high (3044 changed lines across 36 files).
Submitted 3 inline comments.
Reviewed commit 3245b4f.
| return std::nullopt; | ||
| } | ||
|
|
||
| this->Train(data); |
There was a problem hiding this comment.
[P1] Validate dimensions before optimized training
Build now reaches Train(data) before Add calls validate_add_data. For an eligible split-RaBitQ index and a dataset whose dimension is smaller than the configured index dimension, RaBitQuantizer::TrainImpl strides and copies original_dim_ floats per row, reading beyond the supplied vectors; a larger wrong dimension can instead train on mis-strided data and leave the quantizer marked trained even though Add subsequently rejects the build. Validate the dataset before starting training so invalid input remains memory-safe and side-effect-free.
| if (io_type == IO_TYPE_VALUE_READER_IO) { | ||
| return MakeHomogeneousRaBitQSplitDataCell<metric, ReaderIO>(param, common_param); | ||
| } | ||
| return nullptr; |
There was a problem hiding this comment.
[P2] Preserve homogeneous uring_io dispatch
FlattenInterface::MakeInstance still dispatches uring_io to make_instance<UringIO>, but this new split factory has no corresponding homogeneous branch and returns null here. With HAVE_LIBURING=1, a split-RaBitQ configuration using uring_io therefore regresses from constructing RaBitQSplitDataCell<..., UringIO, UringIO> to index creation failure or a later null dereference. Add the guarded UringIO specialization.
| `fast_encode_rabitq` and `fast_encode_rabitq_rounds` are available on HGraph, | ||
| IVF, and Pyramid and are propagated to both base and precise RaBitQ quantizers. | ||
|
|
||
| For a normal first HGraph build with split RaBitQ and `fast_encode_rabitq=true`, |
There was a problem hiding this comment.
[P3] Document the build_by_base prerequisite
The implementation enables this path only when has_precise_reorder() ? build_by_base_ : raw_vector_ == nullptr. A normal split x+y configuration has precise reorder enabled while build_by_base defaults to false; the new functional configurations explicitly set it to true. Consequently, the scalar lifecycle described here does not apply to the normal/default build, so document the build_by_base=true prerequisite and other eligibility constraints or broaden the implementation.
Signed-off-by: LightWant <2510035537@qq.com> Assisted-by: Codex:gpt-5
vsag-bot
left a comment
There was a problem hiding this comment.
Automated inline review completed.
Review effort: high (3030 changed lines across 36 files).
Submitted 3 inline comments.
Reviewed commit e430b31.
|
|
||
| std::vector<int64_t> result; | ||
| if (graph_type_ == GRAPH_TYPE_VALUE_NSW) { | ||
| this->Train(data); |
There was a problem hiding this comment.
[P1] Validate the dataset before optimized training
This NSW path calls Train before Add reaches validate_add_data. If data->GetDim() differs from the configured dimension, RaBitQuantizer::TrainImpl strides original_dim_ floats per row, so a smaller row can be read out of bounds and a larger row is mis-strided before Add rejects it; validate the dataset before training or mutating the quantizer.
| if (io_type == IO_TYPE_VALUE_READER_IO) { | ||
| return MakeHomogeneousRaBitQSplitDataCell<metric, ReaderIO>(param, common_param); | ||
| } | ||
| return nullptr; |
There was a problem hiding this comment.
[P2] Restore homogeneous uring_io dispatch
FlattenInterface::MakeInstance still routes uring_io split configurations into this factory, but there is no IO_TYPE_VALUE_URING_IO branch, so it now returns null instead of constructing RaBitQSplitDataCell<..., UringIO, UringIO>. With HAVE_LIBURING=1, previously supported split-RaBitQ uring indexes therefore fail creation; add the guarded homogeneous specialization.
| `fast_encode_rabitq` and `fast_encode_rabitq_rounds` are available on HGraph, | ||
| IVF, and Pyramid and are propagated to both base and precise RaBitQ quantizers. | ||
|
|
||
| For a normal first HGraph build with split RaBitQ and `fast_encode_rabitq=true`, |
There was a problem hiding this comment.
[P3] Document the optimized-build eligibility constraints
This is not enabled for every normal split-RaBitQ first build: when precise reorder exists, the session requires build_by_base=true, while configurations using precise codes, deduplicated storage, raw-vector graph construction, or non-fast encoding fall back. State these prerequisites in both language versions so users do not plan memory or performance around a path that will not run.
Signed-off-by: LightWant <2510035537@qq.com> Assisted-by: Codex:gpt-5
vsag-bot
left a comment
There was a problem hiding this comment.
Automated inline review completed.
Review effort: high (3022 changed lines across 36 files).
Submitted 2 inline comments.
Reviewed commit a25d8c6.
| if (io_type == IO_TYPE_VALUE_READER_IO) { | ||
| return MakeHomogeneousRaBitQSplitDataCell<metric, ReaderIO>(param, common_param); | ||
| } | ||
| return nullptr; |
There was a problem hiding this comment.
[P2] [P2] Restore homogeneous uring_io dispatch
FlattenInterface::MakeInstance still sends IO_TYPE_VALUE_URING_IO split configurations to this factory, but no branch handles that type. Under HAVE_LIBURING=1, a configuration that previously instantiated RaBitQSplitDataCell<..., UringIO, UringIO> reaches this return and produces a null cell, causing index creation to fail or later dereference the null pointer. Restore the homogeneous UringIO specialization.
| `fast_encode_rabitq` and `fast_encode_rabitq_rounds` are available on HGraph, | ||
| IVF, and Pyramid and are propagated to both base and precise RaBitQ quantizers. | ||
|
|
||
| For a normal first HGraph build with split RaBitQ and `fast_encode_rabitq=true`, |
There was a problem hiding this comment.
[P3] [P3] State the optimized-build eligibility constraints
The scalar lifecycle is not used by every normal split build described here: when precise reorder exists, it requires build_by_base=true even though that option defaults to false, and loaded-cache, deduplicated-storage, raw-vector, non-fast, and one-bit configurations also bypass it. This overstates the temporary-memory and performance behavior for common configurations; qualify the lifecycle in both language versions with the actual eligibility constraints.
Change Type
Linked Issue
Not required for kind/improvement.
What Changed
Test Evidence
Test details:
Compatibility Impact
Performance and Concurrency Impact
Documentation Impact
Risk and Rollback
Checklist