文档

pgvector兼容模式使用指南

更新时间:

pgvector是基于PostgreSQL数据库的开源向量化数据的工具包。使用pgvector可以方便地构建向量索引,执行向量之间的相似度计算和查询,常用于向量相似度搜索、推荐系统、聚类分析等场景。

前提条件

使用pgvector兼容模式前,请先满足以下条件:

pgvector兼容模式说明

对于使用pgvector做向量检索引擎的业务,AnalyticDB PostgreSQL版向量数据库对pgvector的向量读写操作可以完全兼容,只需要修改索引构建的SQL语法即可。因此使用pgvector做向量检索的业务可以完全无缝迁移到AnalyticDB PostgreSQL版向量数据库中,基本不需要对业务侧的代码做改动。相比于原生的pgvector向量检索引擎,AnalyticDB PostgreSQL版向量数据库的pgvector兼容模式具有以下优势:

  • 基本上完全兼容pgvector的SQL语法,可以完全复用pgvector生态的客户端。

  • pgvector目前主要在单机PostgreSQL数据库上使用,而AnalyticDB PostgreSQL版向量数据库是分布式版,能处理更大的向量数据量。

  • AnalyticDB PostgreSQL版向量数据库使用自研的FastANN向量检索引擎,具备比原生pgvector更优秀的性能,详情请查看向量分析性能测试

  • 同时AnalyticDB PostgreSQL版向量数据库在优化器和执行器层面打通了混合查询计划生成与混合查询执行算子,具备非常完备的混合查询能力,而原生pgvector基本不具备混合查询的能力(只能通过分区等手段实现简单的场景)。

  • AnalyticDB PostgreSQL版向量数据库拥有Float2类型,可以对向量表存储进行压缩;也具备PQ量化能力,可以对向量索引存储进行压缩。因此AnalyticDB PostgreSQL版向量数据库相比于原生pgvector,也具有存储成本的优势。

创建向量表

创建兼容pgvector语法的向量表和AnalyticDB PostgreSQL版中原生向量表的语法相同,只是表中的向量列由数组(smallint[]float2[]float4[])类型改为了vector类型(pgvector定义的向量类型),并且一个表可以支持多个向量列。

语法

CREATE TABLE [TABLE_NAME]
(  
    C1 DATATYPE,  
    C2 DATATYPE,  
    ......,  
    CN VECTOR(DIM), 
    PRIMARY KEY(C1 [,C2,...CN])
) DISTRIBUTED BY(C1);

其中CN为向量列,为vector类型,参数DIM为向量的维度。

示例

创建一个命名为FACE_TABLE的向量表,其中C1为主键,C2和C3均为向量列,具体示例如下:

CREATE TABLE FACE_TABLE (  
    C1 INT,  
    C2 VECTOR(512) NOT NULL, 
    C3 VECTOR(1536) NOT NULL, 
    C4 TIMESTAMP NOT NULL,  
    C5 VARCHAR(20) NOT NULL,  
    PRIMARY KEY (C1)
) DISTRIBUTED BY (C1);

创建向量索引

在pgvector语法的向量表上添加向量索引的方式和AnalyticDB PostgreSQL版向量数据库原生的向量索引创建方式完全一致,并且一个向量表上的每个向量列都可以创建多个向量索引。

语法

CREATE INDEX [INDEX_NAME]
ON [SCHEMA_NAME].[TABLE_NAME]   
USING ANN(COLUMN_NAME) 
WITH (DIM=<DIMENSION>,
      DISTANCEMEASURE=<MEASURE>,
      HNSW_M=<M>,
      HNSW_EF_CONSTRUCTION=<EF_CONSTURCTION>,
      PQ_ENABLE=<PQ_ENABLE>,
      PQ_SEGMENTS=<PQ_SEGMENTS>,
      PQ_CENTERS=<PQ_CENTERS>,
      EXTERNAL_STORAGE=<EXTERNAL_STORAGE>;

由于pgvector的vector类型已经包含了维度信息,创建索引中的DIM可以不填,其他参数可以查看原生向量索引的语法创建规则,详情请参见创建向量索引

示例

在上文的FACE_TABLE的向量表上继续创建索引,具体示例如下:

-- 在向量列C2上创建三种向量索引。
CREATE INDEX idx_c2_l2 ON FACE_TABLE USING ann(C2) WITH (distancemeasure=l2, hnsw_m=64, pq_enable=1);
CREATE INDEX idx_c2_ip ON FACE_TABLE USING ann(C2) WITH (distancemeasure=ip, hnsw_m=64, pq_enable=1);
CREATE INDEX idx_c2_cosine ON FACE_TABLE USING ann(C2) WITH (distancemeasure=cosine, hnsw_m=64, pq_enable=1);
-- 在向量列C3上创建三种向量索引。
CREATE INDEX idx_c3_l2 ON FACE_TABLE USING ann(C3) WITH (distancemeasure=l2, hnsw_m=64, pq_enable=1);
CREATE INDEX idx_c3_ip ON FACE_TABLE USING ann(C3) WITH (distancemeasure=ip, hnsw_m=64, pq_enable=1);
CREATE INDEX idx_c3_cosine ON FACE_TABLE USING ann(C3) WITH (distancemeasure=cosine, hnsw_m=64, pq_enable=1);

该示例中列举了在多个向量列上创建多个向量索引,在实际使用过程中需根据实际使用情况进行创建,以避免创建无效索引。

向量数据导入

兼容pgvector语法的向量表的向量数据导入完全兼容pgvector的语法。以上文的FACE_TABLE表为例说明INSERT的使用方法,具体示例如下:

INSERT INTO FACE_TABLE 
values (1, '[1,2,3 ... 512]', '[1,2,3 ... 1536]', '2023-12-29 00:00:00', 'aaa.bbb.ccc/face1.jpg');

向量检索

对于使用pgvector语法的向量表,向量检索的语法和pgvector原生语法完全兼容,可以直接使用pgvector的原生查询方式进行查询。

与向量检索召回率相关的内核参数与AnalyticDB PostgreSQL版向量数据库的原生参数一致,详情请参见向量检索。以FACE_TABLE为例说明向量检查的具体使用方式:

-- 精确搜索方式:按欧氏距离排序。
SELECT C1 FROM FACE_TABLE ORDER BY vector_l2_squared_distance(C2, '[1,2,3 ... 512]') LIMIT 10;
-- 精确搜索方式:按内积距离排序。
SELECT C1 FROM FACE_TABLE ORDER BY vector_negative_inner_product(C2, '[1,2,3 ... 512]') LIMIT 10;
-- 精确搜索方式:按余弦相似度排序。
SELECT C1 FROM FACE_TABLE ORDER BY cosine_distance(C2, '[1,2,3 ... 512]') LIMIT 10;

-- 近似搜索方式:按欧氏距离排序。
SELECT C1 FROM FACE_TABLE ORDER BY C2 <-> '[1,2,3 ... 512]' LIMIT 10;
-- 近似搜索方式:按内积距离排序。
SELECT C1 FROM FACE_TABLE ORDER BY C2 <#> '[1,2,3 ... 512]' LIMIT 10;
-- 近似搜索方式:按余弦相似度排序。
SELECT C1 FROM FACE_TABLE ORDER BY C2 <=> '[1,2,3 ... 512]' LIMIT 10;

由于已经在FACE_TABLE表的C2列上建了欧氏距离,内积距离和余弦相似度三种距离度量的索引,因此示例中的三种近似搜索方式均能命中对应的向量索引。在实际使用的过程中,需要注意近似查询方式中的操作符<-><#><=>必须与向量索引的距离度量一一对应,否则如果没有对应的距离度量的索引,将会退化为精确搜索。

向量检索的SQL优化

  • 当需要返回向量的距离score,您可以使用下面的SQL来提升性能。直接在向量索引的排序值基础上进行计算得到最终的score,可以节省大量的计算耗时,具体示例如下:

    -- 按欧氏距离排序的向量检索。
    SELECT t.C1 as C1, sqrt(t.score) as score 
    FROM 
      (SELECT C1,C2 <-> '[1,2,3 ... 512]' as score
       FROM FACE_TABLE
       ORDER BY score LIMIT topk) t;
    
    -- 按内积距离排序的向量检索。
    SELECT t.C1 as C1, (-1 * t.score) as score
    FROM
      (SELECT C1, C2 <#> '[1,2,3 ... 512]' as score
       FROM FACE_TABLE
       ORDER BY score LIMIT topk) t;
    
    -- 按余弦相似度排序的向量检索。
    SELECT t.C1 as C1, (1.0 - t.score) as score
    FROM 
      (SELECT C1, C2 <=> '[1,2,3 ... 512]' as score
       FROM FACE_TABLE
       ORDER BY score LIMIT topk) t;

    向量检索返回的结果中,score分别为欧氏距离(开方值),内积距离和余弦相似度。

  • 当需要根据score的范围进行过滤并返回结果,您可以使用下面的SQL来实现。利用向量索引的排序值进行计算得到最终的score,可以节省大量的计算耗时,具体示例如下:

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

混合查询

对于使用pgvector语法的向量表,混合查询的方式与AnalyticDB PostgreSQL版向量数据库的原生语法完全一致,详情请参见混合检索使用指南。下文以FACE_TABLE举例说明混合查询使用方法。

SELECT C1 FROM FACE_TABLE WHERE
  C4 > '2023-10-01 00:00:00' AND C4 < '2024-01-01 00:00:00'
ORDER BY 
  C2 <-> '[1,2,3 ... 512]'
LIMIT 10;

相关参考

pgvector多种语言的客户端

语言

客户端库代码地址

C

pgvector-C

C++

pgvector-cpp

Go

pgvector-go

Java,Kotlin,Groovy,Scala

pgvector-java

PHP

pgvector-php

Python

pgvector-python

Rust

pgvector-rust

pgvector生态的多种语言的客户端均可以无缝接入到AnalyticDB PostgreSQL版向量数据库,只需对向量索引相关的SQL进行修改即可。

支持的向量函数

函数作用

向量函数

返回值类型

含义

支持的数据类型

计算

l2_distance

double precision

欧氏距离(开方值),通常用于衡量两个向量的大小,表示两个向量的距离。

vector

inner_product

double precision

内积距离,在向量归一化之后等于余弦相似度,通常用于在向量归一化之后替代余弦相似度。

vector

cosine_similarity

double precision

余弦相似度,取值范围:[-1, 1],通常用于衡量两个向量在方向上的相似性,而不关心两个向量的实际长度。

vector

vector_dims

integer

计算单个向量的维度。

vector

vector_norm

double precision

计算单个向量的模长。

vector

vector_add

vector

两个向量做加法。

vector

vector_sub

vector

两个向量做减法。

vector

vector_mul

vector

两个向量做乘法。

vector

vector_angle

double precision

计算两个向量的夹角。

vector

排序

vector_l2_squared_distance

double precision

欧氏距离(平方值),由于比欧氏距离(开方值)少了开方的计算,因此主要用于对欧氏距离(开方值)的排序逻辑,以减少计算量。

vector

vector_negative_inner_product

double precision

反内积距离,为内积距离取反后的结果,主要用于对内积距离的排序逻辑,以保证排序结果按内积距离从大到小排序。

vector

cosine_distance

double precision

余弦距离,取值范围:[0, 2],主要用于对余弦相似度的排序逻辑,以保证排序结果按余弦相似度从大到小排序。

vector

表格中向量距离的计算公式详情,请参见创建向量索引

向量函数的使用示例:

-- 欧氏距离
SELECT l2_distance('[1,1,1,1]'::vector, '[2,2,2,2]'::vector);
-- 内积距离
SELECT inner_product('[1,1,1,1]'::vector, '[2,2,2,2]'::vector);
-- 余弦相似度
SELECT cosine_similarity('[1,1,1,1]'::vector, '[2,2,2,2]'::vector);
-- 向量维度
SELECT vector_dims('[1,1,1,1]'::vector);
-- 向量模长
SELECT vector_norm('[1,1,1,1]'::vector);
-- 向量加法
SELECT vector_add('[1,1,1,1]'::vector, '[2,2,2,2]'::vector);
-- 向量减法
SELECT vector_sub('[1,1,1,1]'::vector, '[2,2,2,2]'::vector);
-- 向量乘法
SELECT vector_mul('[1,1,1,1]'::vector, '[2,2,2,2]'::vector);
-- 向量夹角
SELECT vector_angle('[1,1,1,1]'::vector, '[2,2,2,2]'::vector);
-- 欧氏平方距离
SELECT vector_l2_squared_distance('[1,1,1,1]'::vector, '[2,2,2,2]'::vector);
-- 反内积距离
SELECT vector_negative_inner_product('[1,1,1,1]'::vector, '[2,2,2,2]'::vector);
-- 余弦距离
SELECT cosine_distance('[1,1,1,1]'::vector, '[2,2,2,2]'::vector);

支持的向量操作符

操作符

计算含义

排序含义

支持的数据类型

<->

获取欧氏距离(平方),结果等同于l2_squared_distance。

按欧氏距离(平方)从小到大排序。

vector

<#>

获取反内积,结果等同于negative_inner_product_distance。

按点积距离从大到小排序。

vector

<=>

获取余弦距离,结果等同于cosine_distance。

按余弦相似度从大到小排序。

vector

+

两个向量的加法

vector

-

两个向量的减法

vector

*

两个向量的乘法

vector

向量操作符的使用示例:

-- 欧氏距离(平方)
SELECT '[1,1,1,1]'::vector <-> '[2,2,2,2]'::vector AS score;
 
-- 反内积距离
SELECT '[1,1,1,1]'::vector <#> '[2,2,2,2]'::vector AS score;
 
-- 余弦距离
SELECT '[1,1,1,1]'::vector <=> '[2,2,2,2]'::vector AS score;

-- 加法
SELECT '[1,1,1,1]'::vector + '[2,2,2,2]'::vector AS value;

-- 减法
SELECT '[1,1,1,1]'::vector - '[2,2,2,2]'::vector AS value;

-- 乘法
SELECT '[1,1,1,1]'::vector * '[2,2,2,2]'::vector AS value;
  • 本页导读 (1)