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、过滤原语 FilterBitset,以及用于增量搜索的 IteratorContext。已废弃的 SearchParam 在末尾给出以便 迁移。

SearchRequest

声明于 vsag/search_request.hSearchRequest 是一个普通结构体,打包了 Index::SearchWithRequest 的每一个选项。填入你需要的字段,其余 保持默认即可。

vsag::SearchRequest request;
request.query_ = query;      // 含单个查询向量的 DatasetPtr
request.mode_ = vsag::SearchMode::KNN_SEARCH;
request.topk_ = 10;
request.params_str_ = R"({"hgraph": {"ef_search": 100}})";

auto result = index->SearchWithRequest(request);

SearchMode

enum class SearchMode {
    KNN_SEARCH = 1,    // 返回 top-k 个最近向量
    RANGE_SEARCH = 2,  // 返回 radius_ 范围内的所有向量
};

基础字段

字段类型默认值含义
query_DatasetPtrnullptr查询。IVF KNN 请求支持多个查询向量,其他请求只允许一个。
mode_SearchModeKNN_SEARCHKNN 还是范围搜索。
topk_int64_t10要返回的邻居数(KNN 模式)。必须为正。
radius_float0.5距离阈值(范围模式)。非负。
limited_size_int64_t-1范围结果的上限;-1 表示不限。
params_str_std::string""算法特有的搜索参数 JSON(如 ef_search)。

自定义查询距离回调

distance_batch_func_ 可选地让应用提供 query 到向量的分数。它接收稳定的外部向量 ID, 因此闭包可以在 VSAG 之外持有 query 和该 query 的上下文:

request.distance_batch_size_ = 32;
request.distance_batch_func_ = [query](const int64_t* ids, uint64_t count, float* scores) {
    for (uint64_t i = 0; i < count; ++i) {
        scores[i] = Score(query, ids[i]);
    }
};
字段类型默认值含义
distance_batch_func_SearchDistanceBatchFuncnullptr按输入外部 ID 的顺序填写对应分数。分数越小越好,且必须是有限值。
distance_batch_size_uint64_t1单次回调的最大 ID 数。批量推理或外部数据访问应设置为 scorer 的高效批大小;设置回调时必须为正。

回调仅属于当前请求,不参与序列化。它可以捕获 query。hgraph 的回调模式允许 query_ 为 null, 但 ivf 仍需要一个查询向量用于桶路由。回调在一次请求内必须稳定;若调用方启用并行执行则必须 线程安全;不得抛异常,且只能写入有限分数。

brute_force 用该回调执行精确 KNN 和范围搜索。hgraph 仅支持 KNN:回调驱动图遍历和最终 排序,但图仍由配置的内置 metric 构建,因此无法保证该回调分数下的 recall。HGraph 可能为保持 图连通性而计算被过滤的遍历节点,但不会返回这些节点。 回调 HGraph 不支持并行检索或 brute_force_threshold;这些配置会被拒绝,而不会静默改变检索语义。

ivf 支持带回调的 KNN,但必须提供一个非空的单查询向量。IVF 先以配置的内置 metric 选出 scan_buckets_count 个桶,再对这些桶中的候选调用回调。回调决定候选排序,但无法召回未被选中的 桶内向量;增大 scan_buckets_count 可提高 recall。回调 IVF 不支持范围搜索、disable_bucket_scan、 bucket graph 或并行搜索,这些配置会被拒绝。回调模式会自动关闭精排。其他索引不支持该回调。

IVF 桶路由

IVF 可通过 params_str_ 接收 {"ivf":{"scan_buckets_count":N,"disable_bucket_scan":true}}。该仅路由模式按查询返回 N 个 bucket ID,而非向量 label。NumElements() 为查询数,Dim()scan_buckets_countGetIds() 包含桶 ID(空槽位为 -1), GetDistances() 为到各桶中心的距离。不扫描桶内向量,因此过滤器、topk、范围限制、精排和 reasoning 选项均会被忽略。

IVF 桶 ID 旁路

bucket_ids_ 字段允许调用方提供预选的桶 ID,绕过 IVF 的内部桶路由(ClassifyDatasForSearch)。 当非空时,搜索跳过基于质心的选择,仅扫描指定的桶。

字段类型默认值含义
bucket_ids_std::vector<std::vector<int64_t>>{}用于绕过 IVF 路由的预选桶 ID。

语义:

  • (默认):使用正常的桶路由(ClassifyDatasForSearch)。
  • 非空:跳过路由,仅扫描提供的桶 ID。
  • 批量 IVF KNNbucket_ids_ 外层每项对应一个查询向量。 结果为矩形:NumElements() 是查询数,Dim()topk_。 缺失邻居用 -1 和无穷距离填充。

约束:

  • 批量 IVF 搜索仅支持 KNN;不支持自定义查询距离和 reasoning labels。
  • 非空外层向量必须为每个查询向量提供一个非空条目。
  • 每个桶 ID 必须在 [0, bucket_count) 范围内。
  • 重复的桶 ID 会被拒绝。
  • disable_bucket_scan 模式不兼容。
  • 调用方负责桶 ID 的排序(不会自动排序)。

过滤字段

有三种过滤机制可用;当启用了多于一种时,它们以逻辑**与(AND)**组合。

字段类型默认值含义
enable_attribute_filter_boolfalse启用 SQL 风格的属性过滤。
attribute_filter_str_std::string""过滤表达式(见下)。需要 enable_attribute_filter_
enable_filter_boolfalse启用自定义 Filter 回调。
filter_FilterPtrnullptrfilter 对象。需要 enable_filter_
enable_bitset_filter_boolfalse启用 Bitset 过滤。
bitset_filter_BitsetPtrnullptrbitset。Test(id) == true 表示排除该 id。需要 enable_bitset_filter_

attribute_filter_str_ 的语法类似 SQL。示例:

category = 'electronics' AND price != 1000
multi_in(category, ['electronics', 'clothing']) AND multi_notin(color, ['red', 'blue'])

属性过滤(混合搜索)带过滤的搜索

资源与迭代器字段

字段类型默认值含义
search_allocator_Allocator*nullptr逐次搜索 allocator;为 null 时回退到索引 allocator。
enable_iterator_search_boolfalse启用增量(迭代式)搜索。
p_iter_ctx_IteratorContext**nullptr迭代状态的句柄,跨调用复用。
is_last_search_boolfalse标记迭代序列的最后一次调用。
expected_labels_std::vector<int64_t>{}期望出现在结果中的 id;启用对漏召回的推理分析。

搜索路径 Allocator迭代式搜索,allocator 示例见 examples/cpp/313/314

Filter

声明于 vsag/filter.h。实现这个抽象类以表达任意的“是否保留该 id?”逻辑。通过 FilterPtrstd::shared_ptr<Filter>)持有它。

class Filter {
public:
    enum class Distribution { NONE = 0, RELATED_TO_VECTOR };

    virtual bool CheckValid(int64_t id) const = 0;          // true  => 保留该 id
    virtual bool CheckValid(const char* data) const;         // extra-info 变体(默认 true)
    virtual float ValidRatio() const;                        // 保留比例(默认 1.0)
    virtual Distribution FilterDistribution() const;         // 提示(默认 NONE)
    virtual void GetValidIds(const int64_t** valid_ids, int64_t& count) const;
};

约定: Filter::CheckValid(id) 返回 true 表示保留该向量。这与 Index 上的 bitset / std::function<bool(int64_t)> 预过滤重载 相反 —— 在那些重载里 true 表示被过滤掉。选择重载时请牢记这一区别。

成员用途
CheckValid(int64_t id)核心谓词。true 使该 id 保留在结果中。
CheckValid(const char* data)对元素 extra-info 字节的谓词。默认为 true
ValidRatio()预估通过的向量比例;让引擎选择策略。
FilterDistribution()RELATED_TO_VECTOR 提示有效性与向量位置相关。
GetValidIds(...)可选地暴露显式的有效 id 集合。

examples/cpp/301_feature_filter.cpp

Bitset

声明于 vsag/bitset.h。一个按位置索引的紧凑位标志集合,通过 BitsetPtr 持有。它既用作过滤输入,也可 作为工具(如 l2_and_filtering 的返回值)。

static BitsetPtr Random(int64_t length);  // 给定长度的随机 bitset
static BitsetPtr Make();                  // 空 bitset

void Set(int64_t pos, bool value);
void Set(int64_t pos);       // = Set(pos, true)
bool Test(int64_t pos) const;
uint64_t Count();            // 置位的数量
std::string Dump();          // 调试转储

Bitset 被用作搜索预过滤(bitset_filter_,或 KnnSearch / RangeSearchinvalid 参数) 时,Test(id) == true 表示该 id 被过滤掉

IteratorContext

声明于 vsag/iterator_context.h。一个不透明句柄,保存进行中的迭代式搜索的位置,使后续调用能从上一次 停止处继续。

class IteratorContext {
public:
    virtual ~IteratorContext() = default;
};

你无需直接构造或检查它。VSAG 在首次迭代式搜索时分配它;在之后每次调用中把同一个句柄传回 (通过 SearchRequest::p_iter_ctx_,或 KnnSearch 的迭代重载),并在最后一次调用时设置 last-search 标志,以便引擎释放它。见 迭代式搜索

SearchParam(已废弃)

声明于 vsag/search_param.hSearchParam 早于 SearchRequest,仅为已废弃的 KnnSearch(query, k, SearchParam&) 重载而保留。

struct SearchParam {  // [[deprecated]] 请改用 SearchRequest
    bool is_iter_filter{false};
    bool is_last_search{false};
    const std::string& parameters;
    FilterPtr filter{nullptr};
    Allocator* allocator{nullptr};
    IteratorContext* iter_ctx{nullptr};
};

所有新代码请优先使用 SearchRequest + SearchWithRequest SearchParam 以引用方式持有 parameters,因此被引用的字符串必须比该调用活得更久。

参见

  • Index —— 消费这些类型的搜索方法。
  • Dataset —— 构造 query_ 并读取结果。
  • 辅助类型 —— 属性过滤所用的属性值类型。