我正在研究使用 Elastic KNN 搜索功能,据我所知,这就是我们查询 ES 进行 KNN 搜索的方式。
GET my-index/_knn_search
{
"knn": {
"field": "image_vector",
"query_vector": [0.3, 0.1, 1.2],
"k": 10,
"num_candidates": 100
},
"_source": ["name", "file_type"]
}
这里 num_candidates 的最大限制为 10000,从 ES 文档中我看到了这一点 -
The number of nearest neighbor candidates to consider per shard. Cannot exceed 10,000. Elasticsearch collects num_candidates results from each shard, then merges them to find the top k results. Increasing num_candidates tends to improve the accuracy of the final k results.
以上我不是很清楚。这里有一些问题:
我看到类似的问题here但没有正确的答案。
您需要区分 kNN(k 最近邻)和精确搜索。
通过精确搜索(即使用
script_score
查询时),如果您有 1M 个向量,您的查询向量将与每个向量进行比较,您将得到的结果是与查询向量最接近的真实 10 个向量。
使用 kNN 搜索,也称为“近似”最近邻 (ANN),它有点不同,因为您的 1M 向量将根据您的向量搜索引擎(倒排文件索引、KD 树、分层可导航小世界、 ETC)。对于基于 Apache Lucene 的 Elasticsearch,向量以“分层可导航小世界”结构进行索引。在搜索时,HNSW 算法将尝试根据查询向量的最近距离或最高相似度来计算与您的查询向量最接近的 k 个邻居。它可能会找到真实的,也可能不会,因此这些搜索算法具有“近似”性质。为了减少“或不”的几率,我们的想法是访问更多的向量,这就是num_candidates
的作用。
这个想法不是选择一个足够高的 num_candidates
值来访问数据库中的所有向量,因为这会归结为进行精确搜索,为此使用 ANN 算法是没有意义的,只是进行精确搜索,支付执行价格,仅此而已。
。由于 HNSW 图需要按段构建,并且需要搜索每个段,因此理想的情况是只搜索单个段,即一个分片和一个强制合并的段。根据您的数据量以及如果您不断索引新向量,这可能不可行。但你应该朝这个方向优化,即尽可能少的分片和更少的段。
假设您设法将 1M 个向量放入具有单个段的单个分片中,则没有理由具有较高的num_candidates
,因为 HNSW 搜索算法不需要访问超过一定数量的候选者(根据您的用例、约束、数据量、SLA 等来计算),以便找到前 k 个。