向量搜索最佳实践

本文档提供了一些建议,可帮助您优化 Spanner 中向量搜索的性能。

了解 Spanner 基础知识

如需进行有效的 Spanner 向量搜索性能测试,请了解 Spanner 基础知识。例如,由于缓存,立即重新执行同一查询可能会更快。如需测试主要使用热数据的应用的性能,请先执行预热读取。

请参阅以下指南:

Spanner 会根据 数据库拆分并行处理查询。使用持续的生产查询负载进行测试可以实现 基于负载的拆分, 从而通过提高并行度来提高查询性能。如需提高未来负载的并行度,请考虑 预先拆分数据库,尤其是 对于 KNN。

向量搜索最佳实践

本文档介绍了以下向量搜索最佳实践:

为嵌入列添加注解

使用 vector_length为嵌入列添加注解。 此注解可针对 K 最近邻 (KNN) 搜索进行性能优化,并且是 近似最近邻 (ANN) 搜索的前提条件。

使用 top-k 查询

如需查找最近邻,请使用带有 LIMITORDER BY 子句。top-k 查询针对向量搜索进行了高度优化。避免在 WHERE 子句中按距离阈值进行过滤。

例如,不建议使用以下查询:

SELECT d.DocId
FROM Documents AS d
WHERE COSINE_DISTANCE(d.DocEmbedding, @vector) < 1;

请改用以下查询:

SELECT d.DocId
FROM Documents AS d
ORDER BY COSINE_DISTANCE(d.DocEmbedding, @vector)
LIMIT 10;

使用 top-k 查询不仅更简单(因为它消除了距离阈值调整),而且还可针对向量搜索进行专门的性能优化。

LIMIT 子句使用 SQL 字面量

如果 top-k 限制是固定的,请使用 SQL 字面量而不是参数。例如,使用 LIMIT 10 而不是 LIMIT @limit。这会为 Spanner 查询优化器 提供更多信息,以便选择最佳 查询执行计划

使用面向批处理的扫描

向量搜索查询是扫描密集型查询。对于 KNN 查询,请考虑使用 带有 scan_method=batch查询提示的面向批处理的扫描。 这是 ANN 查询的默认扫描方法。

对小型数据集使用 KNN

如果 KNN 足以满足您的延迟预算,请不要创建向量索引。KNN 更准确,避免了索引创建和维护费用,并且在任何过滤后的输入行数较少时,其性能可能优于 ANN。

使用二级索引加快过滤后的 KNN 的速度

如需提高过滤后的 KNN 查询的性能,请在过滤列上创建 二级索引。 例如,请看以下查询:

SELECT d.DocId
FROM Documents AS d
WHERE Category = 'toy'
ORDER BY COSINE_DISTANCE(d.DocEmbedding, @vector)
LIMIT 10;

如果每个类别的文档数量少于几万个,并且您的应用可以接受 100 毫秒的查询延迟,请在 Category 列上创建二级索引。将 DocEmbedding 列存储在索引中:

CREATE INDEX ON Documents(Category) STORING (DocEmbedding);

此索引创建有助于加快过滤后的查询的速度。

对大型数据集使用 ANN

如果在评估过滤条件后行数较多,请创建向量索引并使用 ANN 搜索。有几种技术可以加快使用 ANN 进行过滤的速度:

  • 存储过滤列:如需在遍历向量 搜索时启用过滤,请将过滤列存储在向量索引中。这样可以在执行过程中尽早移除不符合条件的行。

    CREATE VECTOR INDEX ON Documents(DocEmbedding) STORING(Category);
    
  • 键过滤列:如需加快对移除许多结果的高度选择性列 的过滤速度,请将这些列组织为向量索引中的 其他键列。对于这些额外的键,指定完全相等(使用 = 运算符)的查询速度最快。对任何这些额外的键使用 IN 子句都无法实现相同级别的加速。

    CREATE VECTOR INDEX ON Documents(DocEmbedding, Category);
    
  • 避免存储大型列或将其用作键:这样做可能会稀释嵌入的数据块,从而降低读取效率。作为替代方案,请考虑在索引中使用哈希列,并在 top-k 后将原始大型列用作后过滤条件。

  • 创建过滤后的(部分)向量索引:如果您仅查询数据集的子集,并且过滤条件定义了该子集(例如 Category = "Tech"),请创建过滤后的或部分向量索引