Skip to content

feat: add HGraph MCI clique companion index#2385

Open
LightWant wants to merge 8 commits into
antgroup:mainfrom
LightWant:feat/hgraph-mci-companion-clean
Open

feat: add HGraph MCI clique companion index#2385
LightWant wants to merge 8 commits into
antgroup:mainfrom
LightWant:feat/hgraph-mci-companion-clean

Conversation

@LightWant

@LightWant LightWant commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

Add an optional HGraph MCI companion for filtered KNN search. The companion stores clique metadata inside the HGraph index, shares HGraph vector storage, and is not exposed as a standalone public index type.

Changes

  • Add the internal src/algorithm/mci/ module, CliqueDataCell, and MCI searcher used by HGraph filtered search.
  • Integrate MCI into HGraph build, incremental add maintenance, search routing, serialization, memory usage, and GetStats().
  • Clean up MCI parameters: index_param.mci enables build-time MCI by presence, hgraph_valid_ratio_threshold is search-only, MCI search seed parameters are mci_seed_count and mci_seed_ratio, and the default mci_seed_count is 500.
  • Use precise HGraph vector storage for MCI distance computation instead of depending on user-retained raw vectors.
  • Move MCI SIMD-specific code behind src/simd, remove the mci_v3_ file-name prefix, rename the MCI namespace to vsag::mci, and align internal naming/style with VSAG conventions.
  • Add an explicit read-only MemoryIO raw-buffer fast path for contiguous FP32 storage.
  • Update English and Chinese docs, including the note that MCI Add() is for small increments on an existing initial index and should not be used to build an MCI index from empty.
  • Reduce fp32_simd_test.cpp macro expansion in one large Catch2 test to lower GCC debug-info variable tracking pressure in CI.

Tests

git diff --check origin/main
clang-format-15 --dry-run --Werror on changed C++ files
cmake --build build-mkl --target vsag_static -j2
cmake --build build --target simd_test -j2

Compatibility Impact

  • API/ABI compatibility: no breaking public API changes expected.
  • Behavior changes: adds optional HGraph MCI companion support for filtered search.
  • HGraph MCI build config now enables MCI by the presence of index_param.mci; hgraph_valid_ratio_threshold belongs to search parameters.

Performance and Concurrency Impact

  • Performance impact: intended improvement for filtered HGraph search paths when MCI is enabled.
  • Concurrency/thread-safety impact: none expected.

Related

Closes: #2386

@mergify

mergify Bot commented Jul 1, 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+)

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

@LightWant LightWant added kind/feature Brand-new functionality or capabilities 引入全新的功能、新特性或新能力 module/datacell module/index module/testing version/1.0 labels Jul 1, 2026
@LightWant

Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request introduces the HGraph MCI (Maximal Clique Index) Companion feature, which optimizes filtered KNN searches by building and storing clique metadata alongside the HGraph index. The changes span documentation, examples, build configuration updates, and the core algorithms for MCI building, searching, and serialization. The code review identified several critical issues in the new implementation, including a memory corruption bug in ListLinearHeap::initRaw due to an unupdated size variable, a severe query-time performance bottleneck from allocating visited_nodes per search, a data race on num_cliques_per_node in the parallel builder, and potential undefined behavior in changeToCoreOrder upon heap pop failure. Additionally, improvements were suggested to replace raw memory allocations with RAII containers and standard printf statements with the library's logging system.

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.

Comment thread src/algorithm/mci/mci_list_linear_heap.h Outdated
Comment thread src/impl/searcher/mci_searcher.cpp Outdated
Comment thread src/algorithm/mci/mci_v3_builder.cpp Outdated
Comment thread src/algorithm/mci/mci_v3_graph_mce.cpp Outdated
Comment thread src/algorithm/mci/mci_v3_graph_mce.cpp Outdated
Comment thread src/algorithm/mci/mci_v3_mce.cpp Outdated
@LightWant
LightWant force-pushed the feat/hgraph-mci-companion-clean branch 3 times, most recently from fed41a2 to 78b29f3 Compare July 2, 2026 06:41
@mergify mergify Bot added the module/attr label Jul 2, 2026
@wxyucs wxyucs self-assigned this Jul 2, 2026
@LightWant
LightWant force-pushed the feat/hgraph-mci-companion-clean branch from b8eeedc to 25830d9 Compare July 3, 2026 09:37
@vsag-bot

vsag-bot commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

/label S-waiting-on-review
/waiting-on reviewer
/request-review @jiaweizone
/request-review @wxyucs
/request-review @inabao
/request-review @LHT129

LightWant added 6 commits July 7, 2026 07:46
Add an optional HGraph MCI companion that stores clique metadata with HGraph, routes filtered search through an MCI searcher, supports serialization and add maintenance, and documents the companion workflow with a self-contained example.

Signed-off-by: zhuangye.yxw <2510035537@qq.com>
Assisted-by: Codex:gpt-5
Signed-off-by: zhuangye.yxw <2510035537@qq.com>
Assisted-by: Codex:GPT-5
Remove public build-time use_mci and hgraph_valid_ratio_threshold handling from HGraph MCI options, default the search routing threshold to 0.05, and rename MCI source files to drop the v3 file-name suffix.

Signed-off-by: zhuangye.yxw <2510035537@qq.com>
Assisted-by: Codex:GPT-5
Signed-off-by: zhuangye.yxw <2510035537@qq.com>
Assisted-by: Codex:GPT-5
Signed-off-by: zhuangye.yxw <2510035537@qq.com>
Assisted-by: Codex:GPT-5
Signed-off-by: zhuangye.yxw <2510035537@qq.com>
Assisted-by: Codex:GPT-5
Signed-off-by: zhuangye.yxw <2510035537@qq.com>
Assisted-by: Codex:GPT-5
@LightWant
LightWant force-pushed the feat/hgraph-mci-companion-clean branch from 468cc1a to 64c1082 Compare July 7, 2026 07:55
@mergify mergify Bot added the module/simd label Jul 7, 2026
Signed-off-by: zhuangye.yxw <2510035537@qq.com>
Assisted-by: Codex:GPT-5
@wxyucs

wxyucs commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

/review

@vsag-bot
vsag-bot self-requested a review July 16, 2026 11:08
@vsag-bot

vsag-bot commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Automated pull request review completed.

Review effort: high (8275 changed lines across 45 files).

Submitted 8 inline comments.
Review: #2385 (review)

@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 (8275 changed lines across 45 files).
Submitted 8 inline comments.

Reviewed commit 5914e06.

g.edges[g.m] = g.edges[i];
}
}
g.m++;

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.

[P1] Guard the zero-edge graph before incrementing m

When edge is empty, this unconditional increment creates one default (0, 0) edge while g.n remains zero. build_csr() then writes p_idx[1] into a one-element vector; an ASan probe reproduces the heap-buffer-overflow. The optimized builder can reach this state when a seed's nearest candidate is a duplicate (distance limit zero) while the remaining candidates are distinct, so return no cliques before building the CSR when the edge list is empty.

re_id.resize(g.n);
std::fill(re_id.begin(), re_id.begin() + g.n, g.n);

if (in_c.capacity() < g.max_d)

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.

[P1] Resize reusable scratch vectors by size, not capacity

Checking capacity() does not ensure that indices below g.max_d are within the vector's logical size. This is especially immediate for vector<bool>, whose first small resize commonly leaves a capacity of 64: a later seed with a larger degree skips resize(), and this fill plus subsequent indexing run past size(). Reusing one runner for graphs of sizes 5, 8, and 9 aborts under _GLIBCXX_DEBUG; the same issue exists for re_id above, so both checks must use size() or resize unconditionally.

mci_param.metric = this->metric_;
mci_param.used_precise_float_csr = &mci_used_precise_float_csr;
}
search_result = this->mci_searcher_->Search(

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.

[P1] Do not route executor-backed attribute filters to MCI

Attribute filtering is stored in search_param.executors, but both MCI implementations only check is_inner_id_allowed and never run these executors. A request combining a selective user filter with enable_attribute_filter_ can therefore route here and return IDs that violate the attribute expression. Either incorporate the executor-produced filter into MCI's validity check or keep such requests on the HGraph path.

if (row_stride != nullptr) {
*row_stride = this->code_size_ / sizeof(float);
}
return reinterpret_cast<const float*>(memory_io->GetReadOnlyRawData());

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.

[P1] Pin the raw MemoryIO buffer for the duration of MCI search

This returns an unpinned pointer that MemoryIO::ResizeImpl or WriteImpl may invalidate through Reallocate. HGraph search's shared global_mutex_ does not protect insert_persistent_codes(), which runs before Add takes that mutex, so concurrent Add can reallocate the FP32 buffer while search_precise_float_csr() is dereferencing it. The fast path needs a lifetime/read lock spanning the search, or it must be disabled while the index is mutable.

clique_ids.clear();
cliques->CollectNodeCliqueIds(candidate->inner_id, clique_ids);
for (auto clique_id : clique_ids) {
if (visited_cliques.Get(clique_id)) {

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.

[P1] Keep the clique-count snapshot stable during traversal

The visit-mark array is sized from an unlocked TotalLogicalCliqueCount() snapshot, while each later clique lookup takes a separate lock. During a batched concurrent Add, AppendNewClique() can insert another clique between those operations, allowing CollectNodeCliqueIds() to return an ID equal to or above the marks size; visited_cliques.Get() then indexes out of bounds. Hold a stable cell snapshot across traversal, retry on a version change, or grow/check the marks before indexing.

max_norm_error);

auto distance_from_dot = [&](InnerIdType lhs, InnerIdType rhs, float dot) {
const float distance =

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.

[P2] Honor the configured metric in optimized clique distances

The float fast path always constructs local edges from squared-L2 distance, even when HGraph is configured for cosine or inner product; it receives no metric parameter. This disagrees with the generic path's ComputePairVectors() reference behavior, and raw cosine build vectors are not necessarily normalized, so magnitude can completely change clique topology and filtered recall. Pass the metric and reproduce its distance semantics, or restrict this optimized path to L2.

const auto candidate_limit =
std::min<uint64_t>({params.candidate_limit, graph.row_stride, total - 1});
const auto clique_threshold =
std::max<uint64_t>(2, std::min<uint64_t>({params.clique_max, candidate_limit + 1, total}));

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.

[P2] Enforce clique_max as an upper bound

clique_max is used here as a minimum enumeration threshold, and no later step truncates saved cliques to that size. For example, clique_max: 4 can store all nine vertices of a complete local graph, contrary to the documented maximum and with unexpectedly larger memory and query fan-out. Apply an actual upper bound when saving cliques, or correct the public parameter contract if minimum size is intended.

}
}
if (not seed_list_provided) {
for (InnerIdType seed = 0; seed < total and seeds < seed_target; ++seed) {

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.

[P2] Avoid full-index seed scans for callback filters

A normal callback-based Filter does not implement GetValidIds(), so MCI falls back to scanning inner IDs from zero until it finds the requested number of valid seeds. With the sparse filters that trigger MCI, valid IDs near the end can make every query execute millions of filter callbacks, turning the intended sublinear search into an O(total) scan. Use bounded sampling or a reusable valid-ID source, or fall back to HGraph when seed enumeration is unavailable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feat](hgraph): add MCI companion for filtered search

3 participants