向量检索

AnalyticDB PostgreSQL版提供完全按照相似度距离排序的精确检索(搜索速度较慢)和使用HNSW索引的近似索引检索(搜索速度快)两种向量检索方式。

精确检索

完全按照相似度距离排序的暴力搜索。此方式需要比较每一个向量,因此它的搜索速度较慢,但是召回率可以达到百分之百。

欧氏距离、内积距离,余弦相似度三种距离相似度的精确检索使用方式如下:

  • 欧氏距离

    SELECT ID, l2_distance(<VECTOR_COLUMN_NAME>, array[1,2,3...N]::float4[]) as score FROM <TABLE_NAME> ORDER BY l2_squared_distance(<VECTOR_COLUMN_NAME>, array[1,2,3...N]::float4[]) LIMIT <TOPK>;
  • 内积距离

    SELECT ID, inner_product_distance(<VECTOR_COLUMN_NAME>, array[1,2,3...N]::float4[]) as score FROM <TABLE_NAME> ORDER BY negative_inner_product_distance(<VECTOR_COLUMN_NAME>, array[1,2,3...N]::float4[]) LIMIT <TOPK>;
  • 余弦相似度

    SELECT ID, cosine_similarity(<VECTOR_COLUMN_NAME>, array[1,2,3...N]::float4[]) as score FROM <TABLE_NAME> ORDER BY 
    cosine_distance(<VECTOR_COLUMN_NAME>, array[1,2,3...N]::float4[]) LIMIT <TOPK>;

各字段说明:

  • score:在三种检索方式中的score分别表示欧氏距离,内积距离和余弦相似度,并且分别按欧氏距离从小到大排序,按点积距离从大到小排序,按余弦相似度从大到小排序。

  • <VECTOR_COLUMN_NAME>:向量列名称。

  • <TABLE_NAME>:向量表名称。

  • <TOPK>:需要检索的结果集topk。

近似的索引检索

通过使用HNSW索引的方式进行搜索,此方式搜索速度较快,但得到的结果是一个近似的结果,一般召回率都可以达到99%以上。

语法

欧氏距离、内积距离,余弦相似度三种距离相似度的近似的索引检索使用方式如下:

说明

内积距离和余弦相似度在v6.3.10.18及以上版本支持,使用时请确保内核版本满足要求。查看及升级内核版本请参见版本升级

  • 欧氏距离

    SELECT ID, l2_distance(<VECTOR_COLUMN_NAME>, array[1,2,3...N]::float4[]) as score FROM <TABLE_NAME> ORDER BY <VECTOR_COLUMN_NAME> <-> array[1,2,3...N]::float4[] LIMIT <TOPK>;
  • 内积距离

    SELECT ID, inner_product_distance(<VECTOR_COLUMN_NAME>, array[1,2,3...N]::float4[]) as score FROM <TABLE_NAME> ORDER BY <VECTOR_COLUMN_NAME> <#> array[1,2,3...N]::float4[] LIMIT <TOPK>;
  • 余弦相似度

    SELECT ID, cosine_similarity(<VECTOR_COLUMN_NAME>, array[1,2,3...N]::float4[]) as score FROM <TABLE_NAME> ORDER BY <VECTOR_COLUMN_NAME> <=> array[1,2,3...N]::float4[] LIMIT <TOPK>;
说明
  • 上述三种近似的索引检索方式中的各字段说明和精确检索方式中的字段说明相同。

  • 如果没有建立索引,或者FastANN向量检索引擎相关的内核参数没有设置时,上述近似的索引检索将退化为精确检索。

  • 在使用向量索引时,配合向量查询的ORDER BY排序方向必须为ASC或不填。如果需要根据距离降序排序,或在使用向量索引后,再根据其他列排序输出,请将向量查询作为子查询,在父查询中添加需要的ORDER BY语句。

  • 在使用向量索引时,ORDER BY语句必须包含<-><#><=>等操作符,否则不能有效使用向量索引的加速能力。同时<-><#><=>等操作符必须有对应距离度量的向量索引存在,否则也不能使用向量索引的加速能力。支持的操作符及其用法,请参见创建向量索引

示例

以文本知识库为例,如果我们要通过文本搜索它的来源文章,那么我们就可以直接通过向量索引检索进行查找,具体SQL如下:

SELECT id, chunk, intime, url FROM chunks
ORDER BY
    feature <=> array[10,2.0,…, 1536.0]::real[]
LIMIT 100;

您也可以通过添加EXPLAIN的方式来检查该查询的执行计划。

例如如下检查执行计划结果中,可以看到关键词Ann Index Scan,则表明执行计划使用的是向量索引。

QUERY PLAN
-------------------------------------------------
 Limit
   ->  Gather Motion 3:1  (slice1; segments: 3)
         Merge Key: ((feature <=> $0))
          ->  Limit
               ->  Ann Index Scan using feature_idx on chunks
                Order By: (feature <=> $0)
 Optimizer: Postgres query optimizer

如果您的需求是查找最近一个月以内的某个文本的来源文章。那么可以直接通过融合检索进行查找,具体SQL如下:

SELECT id, chunk, intime, url FROM chunks WHERE
    intime > '2023-04-01' AND intime <= '2023-05-01'
ORDER BY
    feature <=> array[10,2.0,…, 1536.0]::real[]
LIMIT 100;

相关参考

向量检索的SQL优化

通过下文示例介绍向量检索的SQL优化。例如,创建向量表如下,向量索引目前支持一个向量列上创建多个向量索引,可以根据需求创建所需的索引,但一定要保证查询的SQL和索引能匹配上。如<->操作符只能使用采用欧氏距离构建的索引;<#>操作符只能使用采用内积距离构建的索引;<=>操作符只能使用采用余弦相似度构建的索引。

CREATE TABLE test_table (
    id serial primary key,
    feature real[]
) distributed by (id);

CREATE INDEX idx_test_table_feature_l2 ON test_table USING ann(feature) WITH (dim=768, distancemeasure=l2, hnsw_m=64, pq_enable=1);
CREATE INDEX idx_test_table_feature_ip ON test_table USING ann(feature) WITH (dim=768, distancemeasure=ip, hnsw_m=64, pq_enable=1);
CREATE INDEX idx_test_table_feature_cosine ON test_table USING ann(feature) WITH (dim=768, distancemeasure=cosine, hnsw_m=64, pq_enable=1);
  • 当不需要返回向量距离的score值时,您可以采用以下SQL进行查询:

    -- 按欧氏距离排序的向量检索。
    SELECT id 
    FROM test_table
    ORDER BY feature <-> array[1,2,3 ... 768]::real[]
    LIMIT topk;
    
    -- 按内积距离排序的向量检索。
    SELECT id
    FROM test_table
    ORDER BY feature <#> array[1,2,3 ... 768]::real[]
    LIMIT topk;
    
    -- 按余弦相似度排序的向量检索。
    SELECT id
    FROM test_table
    ORDER BY feature <=> array[1,2,3 ... 768]::real[]
    LIMIT topk;
  • 当需要返回向量距离的score值时,您可以利用向量索引返回的排序值进行二次计算得到真实的向量距离score,而避免做完整的向量距离计算,以减少计算耗时。具体SQL如下:

    -- 按欧氏距离排序的向量检索。
    SELECT t.id as id, sqrt(t.score) as score 
    FROM 
      (SELECT id,feature <-> array[1,2,3 ... 768]::real[] as score
       FROM test_table
       ORDER BY score LIMIT topk) t;
    
    -- 按内积距离排序的向量检索。
    SELECT t.id as id, (-1 * t.score) as score
    FROM
      (SELECT id, feature <#> array[1,2,3 ... 768]::real[] as score
       FROM test_table
       ORDER BY score LIMIT topk) t;
    
    -- 按余弦相似度排序的向量检索。
    SELECT t.id as id, (1.0 - t.score) as score
    FROM 
      (SELECT id, feature <=> array[1,2,3 ... 768]::real[] as score
       FROM test_table
       ORDER BY score LIMIT topk) t;
  • 当需要根据score的范围进行过滤并返回结果时,您可以使用下面的SQL来实现,该SQL利用了向量索引的排序值进行计算得到最终的score,节省了大量的计算耗时,具体示例如下:

    -- 按欧氏距离排序的向量检索。
    SELECT t.id as id, sqrt(t.score) as score 
    FROM 
      (SELECT id,feature <-> array[1,2,3 ... 768]::real[] as score
       FROM test_table
       ORDER BY score LIMIT topk) t
    WHERE score < 100;
    
    -- 按内积距离排序的向量检索。
    SELECT t.id as id, (-1 * t.score) as score
    FROM
      (SELECT id, feature <#> array[1,2,3 ... 768]::real[] as score
       FROM test_table
       ORDER BY score LIMIT topk) t
    WHERE score > 10;
    
    -- 按余弦相似度排序的向量检索。
    SELECT t.id as id, (1.0 - t.score) as score
    FROM 
      (SELECT id, feature <=> array[1,2,3 ... 768]::real[] as score
       FROM test_table
       ORDER BY score LIMIT topk) t
    WHERE score > 0.5;

向量检索相关的内核参数

向量检索相关的内核参数

功能说明

默认值

取值范围

fastann.build_parallel_processes

向量索引并行构建的进程数, 会根据数据库规格做不同设置。

4

[1, 64]

fastann.pq_amp

在使用PQ向量降维的优化时,向量检索的结果集放大系数,可用于召回率测试。

10

[1, 1000]

fastann.hnsw_max_scan_points

在HNSW索引中做向量检索时,最大扫描点个数,用于提前结束搜索,可用于召回率测试。

6000

[1, 6000000]

fastann.hnsw_ef_search

在HNSW索引中做向量检索时,搜索候选集大小,可用于召回率测试。

400

[10, 10000]

上述内核参数可以在会话级别设置生效。