本页介绍了如何创建和管理 Spanner 向量索引,这些索引使用近似最近邻 (ANN) 搜索和基于树的结构来加快对数据的向量相似度搜索速度。
Spanner 使用专用向量索引来加快近似最近邻 (ANN) 向量搜索的速度。此索引利用了 Google Research 的可扩容最近邻 (ScaNN),这是一种高效的最近邻算法。
向量索引使用基于树的结构来划分数据,从而加快搜索速度。Spanner 提供两级树配置和三级树配置:
- 二级树配置:叶节点 (
num_leaves
) 包含密切相关的向量组以及相应的形心。根级由所有叶节点的形心组成。 - 三级树配置:在概念上与二级树类似,但引入了一个额外的分支层 (
num_branches
),叶节点形心会从该分支层进一步分区,以形成根级别 (num_leaves
)。
Spanner 会为您选择一个索引。不过,如果您知道某个特定索引效果最佳,则可以使用 FORCE_INDEX
提示来选择使用最适合您的用例的向量索引。
如需了解详情,请参阅 VECTOR INDEX
语句。
限制
- 您无法预先拆分向量索引。如需了解详情,请参阅预拆分概览。
创建向量索引
为优化向量索引的召回率和性能,我们建议您:
在将大部分包含嵌入的行写入数据库后,创建向量索引。插入新数据后,您可能还需要定期重建向量索引。如需了解详情,请参阅重建向量索引。
使用
STORING
子句在向量索引中存储列的副本。如果列值存储在向量索引中,则 Spanner 会在索引的叶级执行过滤,以提升查询性能。如果列用于过滤条件,建议您存储该列。如需详细了解如何在索引中使用STORING
,请参阅为纯索引扫描创建索引。
创建表时,嵌入列必须是 FLOAT32
(推荐)或 FLOAT64
数据类型的数组,并且具有 vector_length 注解,用于指明向量的维度。
以下 DDL 语句会创建一个 Documents
表,其中包含一个向量长度为 DocEmbedding
的嵌入列:
CREATE TABLE Documents (
UserId INT64 NOT NULL,
DocId INT64 NOT NULL,
Author STRING (1024),
DocContents Bytes(MAX),
DocEmbedding ARRAY<FLOAT32>(vector_length=>128) NOT NULL,
NullableDocEmbedding ARRAY<FLOAT32>(vector_length=>128),
WordCount INT64,
) PRIMARY KEY (DocId);
填充 Documents
表后,您可以使用余弦距离在 Documents
表上创建一个具有嵌入列 DocEmbedding
的双层树和 1000 个叶节点的向量索引:
CREATE VECTOR INDEX DocEmbeddingIndex
ON Documents(DocEmbedding)
STORING (WordCount)
OPTIONS (distance_type = 'COSINE', tree_depth = 2, num_leaves = 1000);
如果您的嵌入列未在表定义中标记为 NOT NULL
,您必须在向量索引定义中使用 WHERE COLUMN_NAME IS NOT NULL
子句声明该列,其中 COLUMN_NAME
是您的嵌入列的名称。如需使用余弦距离在可为 null 的嵌入列 NullableDocEmbedding
上创建具有三级树和 1000000 个叶节点的向量索引,请执行以下操作:
CREATE VECTOR INDEX DocEmbeddingThreeLevelIndex
ON Documents(NullableDocEmbedding)
STORING (WordCount)
WHERE NullableDocEmbedding IS NOT NULL
OPTIONS (distance_type = 'COSINE', tree_depth = 3, num_branches=1000, num_leaves = 1000000);
过滤向量索引
您还可以创建过滤后的向量索引,以查找数据库中与过滤条件最匹配的相似项。过滤后的向量索引会选择性地为满足指定过滤条件的行编制索引,从而提高搜索性能。
在以下示例中,表 Documents2
具有一个名为 Category
的列。在矢量搜索中,我们希望为“技术”类别编制索引,因此我们创建了一个生成的列,如果未满足类别条件,则该列的计算结果为 NULL
。
CREATE TABLE Documents2 (
DocId INT64 NOT NULL,
Category STRING(MAX),
NullIfFiltered BOOL AS (IF(Category = 'Tech', TRUE, NULL)) HIDDEN,
DocEmbedding ARRAY<FLOAT32>(vector_length=>128),
) PRIMARY KEY (DocId);
然后,我们创建一个带有过滤条件的向量索引。TechDocEmbeddingIndex
向量索引仅对“技术”类别中的文档编制索引。
CREATE VECTOR INDEX TechDocEmbeddingIndex
ON Documents2(DocEmbedding)
STORING(NullIfFiltered)
WHERE DocEmbedding IS NOT NULL AND NullIfFiltered IS NOT NULL
OPTIONS (...);
当 Spanner 运行以下查询时,如果查询的过滤条件与 TechDocEmbeddingIndex
匹配,系统会自动选择 TechDocEmbeddingIndex
并通过它来加速查询。该查询仅搜索“技术”类别中的文档。您还可以使用 {@FORCE_INDEX=TechDocEmbeddingIndex}
强制 Spanner 明确使用 TechDocEmbeddingIndex
。
SELECT *
FROM Documents2
WHERE DocEmbedding IS NOT NULL AND NullIfFiltered IS NOT NULL
ORDER BY APPROX_(....)
LIMIT 10;
后续步骤
详细了解 Spanner 近似最近邻。
详细了解 GoogleSQL
APPROXIMATE_COSINE_DISTANCE()
、APPROXIMATE_EUCLIDEAN_DISTANCE()
、APPROXIMATE_DOT_PRODUCT()
函数。详细了解矢量索引最佳实践。