Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

搜索归因分析(召回诊断)

搜索归因是一种逐查询的诊断机制,用于解释每个期望的标签是否被召回以及原因。通过填充 SearchRequest::expected_labels_ 并调用 SearchWithRequest 来启用;结果数据集会携带一 份 JSON 报告,可通过 Dataset::GetReasoning() 获取。

快速开始

以下示例假设已构建 SINDI_V2 索引,且 query_dataset 包含一个稀疏查询向量:

// 填充关注的标签
vsag::SearchRequest request;
request.expected_labels_ = {100, 200, 300};
request.query_ = query_dataset;
request.topk_ = 10;
request.params_str_ = R"({"sindi_v2": {"n_candidate": 100}})";

auto results = index->SearchWithRequest(request);
if (!results.has_value()) {
    std::cerr << "SearchWithRequest failed: " << results.error().message << std::endl;
} else {
    std::cout << results.value()->GetReasoning() << std::endl;
}

报告格式 (v1)

完整报告是包含 expected_analysis 和 meta 两个顶级分组的 JSON 对象。 MakeStatusReport 生成的仅状态报告只包含 meta,其中仅有 schema_version、status 和 index_type 三个字段;不包含 expected_analysis 或其余元数据字段。使用方必须检查 meta.status,并将这些附加字段视为可选,而不能要求所有报告都具备完整结构。

例如,空 IVF 索引的仅状态报告为:

{"meta":{"schema_version":1,"status":"empty_index","index_type":"IVF"}}

expected_analysis

字段类型描述
summarystring“M/N expected labels found, P missed”
missed_targetsarray每个缺失标签一个条目

每个 missed_targets 条目:

字段类型描述
labelint原始标签
inner_idint内部 ID
diagnosisstring下列诊断值之一
true_distancefloat真实距离
quantized_distancefloat搜索过程中观察到的近似距离
was_visitedbool该 ID 是否被访问过
visited_at_hopint首次访问时的 hop 编号(-1 表示从未访问)
was_evictedbool是否从候选集中被淘汰
filter_rejectedbool是否被过滤器拒绝
reorder_evictedbool是否被重排序淘汰

meta

字段类型描述
schema_versionint始终为 1
statusstring当前会输出:ok、empty_index。保留状态,当前不会输出:skipped_range_search、unsupported_by_index。
index_typestringHGraph, IVF, SINDI 等

以下元数据字段属于完整报告,不会出现在 MakeStatusReport 输出中;使用方必须允许它们缺失:

字段类型描述
search_modestringknn 或 range
topkint请求的 top k
use_reorderbool是否启用了重排序
filter_activebool是否启用了过滤器
termination_reasonstringnone, lower_bound_reached, hops_limit_reached, timeout
total_hopsint总搜索跳数
total_distance_computationsint总距离计算次数
available_diagnoses[string]引擎可产生的所有诊断类型
available_events[string]本次搜索中索引支持的事件
supports_rangebool该索引是否支持范围搜索归因

诊断类型

值含义
success标签出现在结果集中
not_reachable期望的目标从未被访问
filter_rejected过滤器阻止了该条目
quantization_error近似距离与真实距离偏差过大
ef_too_small被访问但被淘汰(尝试增大 ef)
reorder_evicted重排序阶段被淘汰
unknown无法确定原因

对于未命中的目标,诊断按首个匹配规则返回:未访问、过滤拒绝、量化误差、 候选淘汰、重排淘汰,最后为 unknown。因此同时满足条件时,quantization_error 优先于 ef_too_small。量化检查沿用 近似距离 > 1.5 * 真实距离 的启发式, 且仅在真实距离为正时适用;它不是与距离度量无关的误差界,也不能证明量化导致了 未命中,尤其应谨慎解释可能为负的 IP 距离。

完整报告中的 supports_range 是布尔值,表示已注册的范围搜索归因支持,不代表索引是否提供 RangeSearch API;未注册的索引类型返回 false。仅状态报告缺少该字段并不表示 false。

对于范围搜索请求,HGraph 不会使用 expected_labels_ 进行归因,GetReasoning() 仍为 {}。Pyramid 则会拒绝 expected_labels_ 非空的范围搜索请求,并返回参数无效错误。 这两种行为都不会生成 skipped_range_search 或 unsupported_by_index 状态报告; 这两个状态为保留值,当前不会输出。

各索引事件支持

索引KNNRangeVisitEvictionFilter RejectReorderReorder EvictionBucket Selection
HGraph✓—✓✓✓✓✓—
IVF✓✓✓✓✓✓✓✓
SINDI✓✓✓—✓✓✓✓
SINDI_V2✓✓✓✓✓✓✓✓
BruteForce✓✓✓—✓———
WARP✓✓✓—✓———
Pyramid✓—✓✓✓✓✓—

扩展指南

  1. 新增诊断类型:在 reasoning_types.h 中添加 ReasoningDiagnosis 枚举值,在 ToString 中映射,在 reasoning_context.cpp 中添加诊断规则,添加测试并更新文档。
  2. 新增事件类型:在 reasoning_types.h 中添加 ReasoningEvent 枚举值,在 ReasoningContext 中实现 RecordXxx 方法,用 // [reasoning] 标记埋点位置, 更新能力矩阵并补充文档。
  3. 新索引接入:在 reasoning_capability.cpp 中添加能力条目,实现 SearchWithRequest, 插入归因记录钩子。