全部產品
Search
文件中心

AnalyticDB:pgvector相容模式使用指南

更新時間:Mar 15, 2025

pgvector是基於PostgreSQL資料庫的開源向量化資料的工具包。使用pgvector可以方便地構建向量索引,執行向量之間的相似性計算和查詢,常用於向量相似性搜尋、推薦系統、群集等情境。

前提條件

pgvector相容模式優勢

對於使用pgvector作為向量檢索引擎的業務,AnalyticDB for PostgreSQL向量資料庫完全相容pgvector的向量讀寫操作,只需修改索引構建的SQL文法即可。因此,使用pgvector的業務可以無縫遷移到pgvector相容模式中,幾乎不需要改動業務代碼。pgvector相容模式優勢如下:

  • 無需安裝PGVector外掛程式。執行個體開啟向量檢索引擎最佳化後可以直接使用。

  • 完全相容pgvector的SQL文法。pgvector相容模式可以直接複用pgvector生態的用戶端。

  • 分布式架構。pgvector主要適用於單機PostgreSQL資料庫,而pgvector相容模式是分布式架構,能處理更大的向量資料量。

  • 高效能向量檢索引擎。pgvector相容模式使用自研的FastANN向量檢索引擎,效能優於原生pgvector。

  • 混合查詢能力。pgvector相容模式的最佳化器和執行器支援產生和執行混合查詢計劃,具備強大的混合查詢能力,而原生pgvector僅能通過分區等手段實現簡單的情境。

  • 儲存成本優勢。pgvector相容模式支援Float2類型壓縮向量表格儲存體,並具備PQ量化能力壓縮向量索引儲存,從而降低儲存成本。

建立向量表

建立相容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);

建立向量索引

雲原生資料倉儲AnalyticDB PostgreSQL版向量資料庫的pgvector相容模式下向量索引的建立文法,仍然採用FastANN向量檢索引擎的文法,與pgvector的原生文法規則不同,具體可以參考如下所示文法:

文法

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;

開原始碼庫適配

以開源大模型應用研發平台DIFY為例,介紹如何通過簡單的改造,讓使用pgvector的業務應用代碼能快速適配雲原生資料倉儲AnalyticDB PostgreSQL版向量資料庫。主要涉及三個方面的修改:

  • 去除pgvector的外掛程式安裝。由於雲原生資料倉儲AnalyticDB PostgreSQL版向量資料庫並沒有適配pgvector外掛程式,只是在文法上相容了pgvector的向量表讀寫,因此不需要安裝pgvector的外掛程式。雲原生資料倉儲AnalyticDB PostgreSQL版向量資料庫在開通時會預設安裝自研向量檢索引擎外掛程式FastANN,只需要去掉pgvector的外掛程式即可。具體範例程式碼如下:

    # 代碼位於api/core/rag/datasource/vdb/pgvector/pgvector.py
    
    def _create_collection(self, dimension: int):
        cache_key = f"vector_indexing_{self._collection_name}"
        lock_name = f"{cache_key}_lock"
        WITH redis_client.lock(lock_name, timeout=20):
            collection_exist_cache_key = f"vector_indexing_{self._collection_name}"
            if redis_client.get(collection_exist_cache_key):
                RETURN
    
            WITH self._get_cursor() AS cur:
                # 去除下面的pgvector外掛程式安裝
                #cur.execute("CREATE EXTENSION IF NOT EXISTS vector")
                cur.execute(SQL_CREATE_TABLE.format(table_name=self.table_name, dimension=dimension))
                # TODO: CREATE index https://github.com/pgvector/pgvector?tab=readme-ov-file#indexing
            redis_client.set(collection_exist_cache_key, 1, ex=3600)
        
  • 修改向量表建立。由於雲原生資料倉儲AnalyticDB PostgreSQL版向量資料庫是基於PostgreSQL9.4版本,不支援建表時使用using heap文法。雲原生資料倉儲AnalyticDB PostgreSQL版屬於分散式資料庫,需要設定分布鍵。修改向量表建立語句範例程式碼如下:

    # 代碼位於api/core/rag/datasource/vdb/pgvector/pgvector.py
    
    SQL_CREATE_TABLE = """
    CREATE TABLE IF NOT EXISTS {table_name} (
        id uuid PRIMARY KEY,
        text text NOT NULL,
        meta jsonb NOT NULL,
        embedding vector({dimension}) NOT NULL
    ) USING heap; 
    """
    
    # 修改為如下代碼:
    
    SQL_CREATE_TABLE = """
    CREATE TABLE IF NOT EXISTS {table_name} (
        id uuid PRIMARY KEY,
        text text NOT NULL,
        meta jsonb NOT NULL,
        embedding vector({dimension}) NOT NULL
    ) DISTRIBUTED BY (id); 
    """
  • 修改向量索引建立。由於雲原生資料倉儲AnalyticDB PostgreSQL版向量資料庫採用的是自研向量檢索引擎FastANN的向量能力,並不是直接移植的pgvector外掛程式,在向量索引的建立文法上是有區別的,尤其是索引關鍵詞是不同的。因此必須按照雲原生資料倉儲AnalyticDB PostgreSQL版向量資料庫的文法進行索引的建立。具體範例程式碼如下:

    # 代碼位於api/core/rag/datasource/vdb/pgvector/pgvector.py
    
    # 添加建立向量索引的SQL(也可以直接在資料庫上建立索引,不再此添加)
    
    SQL_CREATE_INDEX = """
    CREATE INDEX ON  {table_name} USING ann(embedding) WITH (HNSW_M=16, HNSW_EF_CONSTRUCTION=500, PQ_ENABLE=1);
    """
    
    def _create_collection(self, dimension: int):
        cache_key = f"vector_indexing_{self._collection_name}"
        lock_name = f"{cache_key}_lock"
        WITH redis_client.lock(lock_name, timeout=20):
            collection_exist_cache_key = f"vector_indexing_{self._collection_name}"
            if redis_client.get(collection_exist_cache_key):
                RETURN
    
            WITH self._get_cursor() AS cur:
                # 去除下面的pgvector外掛程式安裝
                #cur.execute("CREATE EXTENSION IF NOT EXISTS vector")
                cur.execute(SQL_CREATE_TABLE.format(table_name=self.table_name, dimension=dimension))
                # TODO: CREATE index https://github.com/pgvector/pgvector?tab=readme-ov-file#indexing
                # 建立ADB-PG向量資料庫的向量索引
                cur.execute(SQL_CREATE_INDEX.format(table_name=self.table_name))
            redis_client.set(collection_exist_cache_key, 1, ex=3600)

相關參考

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;