我在es一开始有向量检索,就开始关注这方面内容了。特别是在8.X之后的版本,更是如此。我也已经把它应用在亿级的生产环境中,用于多模态检索和语义检索,以及RAG相关。
也做过很多的优化:ES 8.x 向量检索性能测试 & 把向量检索性能提升100倍!_elastiknn-CSDN博客
这篇文章再带大家品一品es的向量检索。
k-nearest neighbor (kNN) search | Elasticsearch Guide [8.12] | Elastic
一、es的向量检索在很大程度上依赖页缓存
以下是引用官方文档的描述!
Compared to other types of search, approximate kNN search has specific resource requirements. In particular, all vector data must fit in the node’s page cache for it to be efficient. Please consult the approximate kNN search tuning guide for important notes on configuration and sizing.
也就是说,想要向量检索的性能足够好,内存是至关重要的因素。同时,也说说明它的上限的瓶颈在内存上。
有条件的给足够的内存,去做页缓存,性能一定不会差。
没条件,一定要把磁盘IO提升去。最好是SSD,磁盘组raid10。
二、Elasticsearch 使用HNSW算法进行近似 kNN 搜索
HNSW 是一种基于图的算法,只有当大多数矢量数据保存在内存中时才能有效地工作。您应该确保数据节点至少有足够的 RAM 来保存向量数据和索引结构。要检查矢量数据的大小,您可以使用分析索引磁盘使用情况API。作为一个宽松的经验法则,并假设默认的 HNSW 选项,使用的字节将为num_vectors * 4 * (num_dimensions + 12).使用时byte element_type 所需的空间会更接近 num_vectors * (num_dimensions + 12)。请注意,所需的 RAM 用于文件系统缓存,它与 Java 堆分开。
数据节点还应该为其他需要 RAM 的方式留下缓冲区。
三、向量相似度算法支持
l2_norm
根据向量之间的 L 2距离(也称为欧几里得距离)计算相似度。该文档_score
计算为 1 / (1 + l2_norm(query, vector)^2)
。
dot_product
计算两个单位向量的点积。此选项提供了执行余弦相似度的优化方法。约束和计算得分由 定义element_type
。
当element_type
是 时float
,所有向量都必须是单位长度,包括文档向量和查询向量。该文档_score
计算为 (1 + dot_product(query, vector)) / 2
。
当element_type
是 时byte
,所有向量必须具有相同的长度,包括文档向量和查询向量,否则结果将不准确。文档的_score
计算方式为 0.5 + (dot_product(query, vector) / (32768 * dims))
其中dims
是每个向量的维度数。
cosine
计算余弦相似度。请注意,执行余弦相似度的最有效方法是将所有向量归一化为单位长度,然后使用 dot_product
。仅cosine
当需要保留原始向量且无法提前对其进行标准化时才应使用。该文档_score
计算为(1 + cosine(query, vector)) / 2
。相似cosine
性不允许向量具有零幅度,因为在这种情况下未定义余弦。
max_inner_product
计算两个向量的最大内积。这与 类似dot_product
,但不需要向量进行归一化。这意味着每个向量的大小都会显着影响分数。该文档_score
已进行调整以防止出现负值。对于max_inner_product
价值观来说< 0
,_score
是 1 / (1 + -1 * max_inner_product(query, vector))
。对于非负max_inner_product
结果,_score
计算max_inner_product(query, vector) + 1
。
四、如何选择——向量函数适用于不同的场景
-
cosine_similarity:
- 适用场景:当你需要衡量两个向量在方向上的相似性而不是它们的大小时,
cosine_similarity
是一个很好的选择。这在文本相似性搜索、推荐系统和语义分析中非常有用。 - 特点:余弦相似度不依赖于向量的长度,因此它适用于比较不同长度的向量或者在向量长度不具有重要意义的情况下。
- 适用场景:当你需要衡量两个向量在方向上的相似性而不是它们的大小时,
-
dot_product:
- 适用场景:
dot_product
适用于当你需要计算两个向量在数量上的相似性,同时考虑它们的方向和大小时。这在推荐系统、图像识别和任何需要考虑向量大小的场景中很有用。 - 特点:点积考虑了向量的长度和方向,因此它可以提供更全面的相似性度量。
- 适用场景:
-
l2_norm:
- 适用场景:
l2_norm
(欧几里得范数)适用于当你需要计算向量间的直线距离时。这在地理空间数据的搜索、聚类分析和任何需要精确度量向量间“实际”距离的场景中非常有用。 - 特点:L2范数计算的是向量分量平方和的平方根,它提供了一个直观的距离度量,符合我们对物理距离的直觉。
- 适用场景:
max_inner_product
是 Elasticsearch 中的一个脚本函数,用于计算两个向量之间的最大内积(点积)。这个函数在处理向量空间模型时特别有用,尤其是在需要找到与给定查询向量最相关的文档时。以下是max_inner_product
函数的一些适用场景-
推荐系统:
- 在推荐系统中,
max_inner_product
可以用来找到与用户兴趣向量最匹配的项目或内容。例如,如果用户的兴趣向量是基于他们过去的行为(如评分、浏览历史等)构建的,那么可以使用max_inner_product
来找到最可能吸引用户的内容。
- 在推荐系统中,
-
语义搜索:
- 对于语义搜索,
max_inner_product
可以帮助识别与查询语义上最相关的文档。通过将文本转换为向量(例如,使用词嵌入或文档嵌入),max_inner_product
可以衡量查询向量与文档向量之间的相似度。
- 对于语义搜索,
-
相似性排名:
- 在执行相似性搜索时,
max_inner_product
可以用来对搜索结果进行排名。通过计算每个文档与查询向量的内积,可以确定哪些文档与用户的查询最相关,并据此对结果进行排序。
- 在执行相似性搜索时,
-
内容过滤:
- 在内容过滤场景中,
max_inner_product
可以用来确定哪些内容与特定的标准或准则最匹配。例如,可以用来过滤出与特定主题或品牌最相关的文章或产品。
- 在内容过滤场景中,
-
数据聚类:
- 在数据聚类分析中,
max_inner_product
可以帮助识别数据点之间的相似性,从而将相似的数据点归为一类。这在市场细分、用户分群等场景中非常有用。
- 在数据聚类分析中,
-
异常检测:
- 虽然
max_inner_product
主要用于找到相似性,但它也可以在异常检测中发挥作用。通过计算数据点与已知正常数据集的内积,可以识别出与正常模式显著不同的异常点。
- 虽然
-
在选择使用哪种向量函数时,需要考虑你的具体需求和数据的特性。例如,如果你的数据是文本或词语嵌入,并且你更关心文档内容的语义相似性,那么cosine_similarity
可能是更好的选择。如果你在处理图像数据,并且关心图像内容的精确相似性,那么dot_product
或l2_norm
可能更适合。
五、语义相似度,选 max_inner_product 还是 cosine_similarity
max_inner_product
和 cosine_similarity
都可以用来计算文本相似度,但它们在适用性和计算方式上有所不同。选择哪一个更适合做文本相似度匹配取决于具体的应用场景和需求。
-
max_inner_product:
max_inner_product
计算的是两个向量之间的点积(内积),它衡量的是向量在数量上的相似性,同时考虑了向量的方向和大小。- 在文本相似度匹配中,如果文本向量的长度(维度)和幅度(向量的大小)都很重要,那么
max_inner_product
可能是一个合适的选择。例如,在广告系统中,如果广告和用户查询的向量长度相同,且我们关心的是广告内容与查询内容在数量上的匹配程度,那么max_inner_product
可以用来找到与用户查询最相关的广告。
-
cosine_similarity:
cosine_similarity
计算的是两个向量之间的余弦相似度,它衡量的是向量在方向上的相似性,而忽略了向量的大小。- 在文本相似度匹配中,如果文本向量的长度(维度)不重要,我们只关心向量的方向是否一致,即文本内容的语义是否相似,那么
cosine_similarity
是一个更好的选择。例如,在信息检索系统中,我们通常关心的是文档内容的语义匹配程度,而不是文档的长度或特定关键词的出现频率,这时cosine_similarity
可以用来找到与用户查询语义上最相关的文档。
总结来说,如果你的应用场景更关注文本内容的语义相似性,而不太关心文本的长度或特定关键词的权重,cosine_similarity
是更合适的选择。相反,如果你需要考虑文本的长度和数量上的匹配程度,max_inner_product
可能更适合你的需求。在实际应用中,通常 cosine_similarity
在文本相似度匹配中更为常见,因为它能够有效地处理文本数据的稀疏性和高维性问题。
六、要检索速度还是准确度?
为了收集结果,kNN 搜索 APInum_candidates在每个分片上查找多个近似最近邻候选者。搜索计算这些候选向量与查询向量的相似度,k 从每个分片中选择最相似的结果。然后,搜索会合并每个分片的结果,以返回全局顶级k最近邻居。
您可以增加num_candidates搜索速度以获得更准确的结果,但代价是搜索速度变慢。具有高值的搜索会num_candidates 考虑每个分片中的更多候选者。这需要更多时间,但搜索找到真正的k顶部最近邻居的概率更高。
同样,您可以减少num_candidates更快的搜索,但结果可能不太准确。
七、选择近似向量搜索还是精确向量搜索?
Elasticsearch 使用HNSW 算法来支持高效的 kNN 搜索。与大多数 kNN 算法一样,HNSW 是一种近似方法,它牺牲结果精度来提高搜索速度。这意味着返回的结果并不总是真正的k 个最近邻。
要运行精确的 kNN 搜索,请使用script_score带有向量函数的查询。代价是暴力遍历,时间成本很大,资源花费成本也很大。