全部產品
Search
文件中心

ApsaraDB RDS:高維向量相似性搜尋(pgvector)

更新時間:Jun 19, 2024

RDS PostgreSQL支援pgvector外掛程式,提供了一個新的資料類型,能夠方便快捷地對高維向量進行檢索,是一款功能強大的向量相似性匹配搜尋外掛程式。

背景

RDS PostgreSQL支援pgvector外掛程式,能夠儲存向量類型資料,並實現向量相似性匹配,為AI產品提供底層資料支援。

pgvector主要提供如下能力:

  • 支援資料類型vector,能夠對向量資料存放區以及查詢。

  • 支援精確和近似最近鄰搜尋(ANN,Approximate Nearest Neighbor),其距離或相似性度量方法包括歐氏距離(L2)、餘弦相似性(Cosine)以及內積運算(Inner Product)。索引構建支援HNSW索引、並行索引IVFFlat、向量的逐元素乘法、L1距離函數以及求和彙總。

  • 最大支援建立16000維度向量,最大支援對2000維度向量建立索引。

相關概念及實現原理

嵌入

嵌入(embedding)是指將高維資料對應為低維表示的過程。在機器學習和自然語言處理中,嵌入通常用於將離散的符號或對象表示為連續的向量空間中的點。

在自然語言處理中,詞嵌入(word embedding)是一種常見的技術,它將單詞映射到實數向量,以便電腦可以更好地理解和處理文本。通過詞嵌入,單詞之間的語義和文法關係可以在向量空間中得到反映。

說明

您可以前往如下常見的嵌入工具/庫官方文檔瞭解更多內容:

實現原理

  1. 嵌入可以將文本、映像、音視頻等資訊在多個維度上抽象,轉化為向量資料。

  2. pgvector提供vector資料類型,使RDS PostgreSQL資料庫具備了儲存向量資料的能力。

  3. pgvector可以對儲存的向量資料進行精確搜尋以及近似最近鄰搜尋。

假設需要將蘋果、香蕉、貓三個Object Storage Service到資料庫中,並使用pgvector計算相似性,實現步驟如下:

  1. 先使用嵌入,將蘋果、香蕉、貓三個對象轉化為向量,假設以二維嵌入為例,結果如下:

    蘋果:embedding[1,1]
    香蕉:embedding[1.2,0.8]
    貓:embedding[6,0.4]
  2. 將嵌入轉化的向量資料存放區到資料庫中。如何將二維向量資料存放區到資料庫中,具體請參見使用樣本

    在二維平面中,三個對象分布如下:

    image..png

對於蘋果和香蕉,都屬於水果,因此在二維座標視圖中二者的距離更接近,而香蕉與貓屬於兩個完全不同的物種,因此距離較遠。

可以對水果的屬性進一步細化,比如水果的顏色,產地,味道等,每一個屬性都是一個維度,也就代表了維度越高,對於該資訊的分類就更細,也就越有可能搜尋出更精確的結果。

應用情境

  • 儲存向量類型資料。

  • 向量相似性匹配搜尋。

前提條件

RDS PostgreSQL執行個體需滿足以下要求:

外掛程式管理

  • 建立外掛程式

    CREATE EXTENSION IF NOT EXISTS vector;
  • 刪除外掛程式

    DROP EXTENSION vector;
  • 更新外掛程式

    ALTER EXTENSION vector UPDATE [ TO new_version ]
    說明

    new_version配置為pgvector的版本,pgvector的最新版本號碼及相關特性,請參見pgvector官方文檔

使用樣本

如下僅是對pgvector的簡單使用樣本,更多使用方法,請參見pgvector官方文檔

  1. 建立一個儲存vector類型的表(items),用於儲存embeddings。

    CREATE TABLE items (
      id bigserial PRIMARY KEY, 
      item text, 
      embedding vector(2)
    );
    說明

    上述樣本中,以二維為例,pgvector最大支援建立16000維度向量。

  2. 將向量資料插入表中。

    INSERT INTO
      items (item, embedding)
    VALUES
      ('蘋果', '[1, 1]'),
      ('香蕉', '[1.2, 0.8]'),
      ('貓', '[6, 0.4]');
  3. 使用餘弦相似性操作符<=>計算香蕉與蘋果、貓之間的相似性。

    SELECT
      item,
      1 - (embedding <=> '[1.2, 0.8]') AS cosine_similarity
    FROM
      items
    ORDER BY
      cosine_similarity DESC;
    說明
    • 在上述樣本中,使用公式cosine_similarity = 1 - cosine_distance進行計算,距離越近,相似性越高。

    • 您也可以使用歐氏距離操作符<->或內積運算操作符<#>計算相似性。

    結果樣本:

    item | cosine_similarity
    ------+--------------------
     香蕉 |                  1
     蘋果 |  0.980580680748848
     貓   |  0.867105556566985

    在上述結果中:

    • 香蕉結果為1,表示完全符合。

    • 蘋果的結果為0.98,表示蘋果與香蕉高度相似。

    • 貓的結果為0.86,表示貓與香蕉相似性較低。

    說明

    您可以在實際業務中設定一個合適的相似性閾值,將相似性較低的結果直接排除。

  4. 為了提高相似性的查詢效率,pgvector支援為向量資料建立索引,執行如下語句,為embedding欄位建立索引。

    CREATE INDEX ON items USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);

    各參數說明如下:

    參數/取值

    說明

    items

    添加索引的表名。

    embedding

    添加索引的列名。

    vector_cosine_ops

    向量索引方法中指定的存取方法。

    • 餘弦相似性搜尋,使用vector_cosine_ops

    • 歐氏距離,使用vector_l2_ops

    • 內積相似性,使用vector_ip_ops

    lists = 100

    lists參數表示將資料集分成的列表數,該值越大,表示資料集被分割得越多,每個子集的大小相對較小,索引查詢速度越快。但隨著lists值的增加,查詢的召回率可能會下降。

    說明
    • 召回率是指在資訊檢索或分類任務中,正確檢索或分類的樣本數量與所有相關樣本數量之比。召回率衡量了系統能夠找到所有相關樣本的能力,它是一個重要的評估指標。

    • 構建索引需要的記憶體較多,當lists參數值超過2000時,會直接報錯ERROR: memory required is xxx MB, maintenance_work_mem is xxx MB,您需要設定更大的maintenance_work_mem才能為向量資料建立索引,該值設定過大執行個體會有很高的OOM風險。設定方法,請參見設定執行個體參數

    • 您需要通過調整lists參數的值,在查詢速度和召回率之間進行權衡,以滿足具體應用情境的需求。

  5. 您可以使用如下兩種方式之一來設定ivfflat.probes參數,指定在索引中搜尋的列表數量,通過增加ivfflat.probes的值,將搜尋更多的列表,可以提高查詢結果的召回率,即找到更多相關的結果。

    • 會話層級

      SET ivfflat.probes = 10;
    • 事務層級

      BEGIN; SET LOCAL ivfflat.probes = 10; SELECT ... COMMIT;

    ivfflat.probes的值越大,查詢結果的召回率越高,但是查詢的速度會降低,根據具體的應用需求和資料集的特性,listsivfflat.probes的值可能需要進行調整以獲得最佳的查詢效能和召回率。

    說明

    如果ivfflat.probes的值與建立索引時指定的lists值相等時,查詢將會忽略向量索引並進行全表掃描。在這種情況下,索引不會被使用,而是直接對整個表進行搜尋,可能會降低查詢效能。

效能資料

為向量資料設定索引時,需要根據實際業務資料量及應用情境,在查詢速度和召回率之間進行權衡,您可以參考如下測試結果進行效能調優。

以下基於RDS PostgreSQL執行個體,分別展示向量資料以及索引在不同資料量下佔用的儲存空間情況,以及在設定不同的lists值以及probes值對查詢效率以及召回率的影響。

測試資料準備

  1. 建立測試資料庫。

    CREATE DATABASE testdb;
  2. 安裝外掛程式。

    CREATE EXTENSION IF NOT EXISTS vector;
  3. 產生固定長度的隨機向量作為測試資料。

    CREATE OR REPLACE FUNCTION random_array(dim integer) 
        RETURNS DOUBLE PRECISION[] 
    AS $$ 
        SELECT array_agg(random()) 
        FROM generate_series(1, dim); 
    $$ 
    LANGUAGE SQL 
    VOLATILE 
    COST 1;
  4. 建立一個儲存1536維向量的表。

    CREATE TABLE vtest(id BIGINT, v VECTOR(1536));
  5. 向表中插入資料。

    INSERT INTO vtest SELECT i, random_array(1536)::VECTOR(1536) FROM generate_series(1, 100000) AS i;
  6. 建立索引。

    CREATE INDEX ON vtest USING ivfflat(v vector_cosine_ops) WITH(lists = 100);

測試步驟

為避免網路延遲等因素對測試資料的影響,推薦使用內網串連地址,本樣本是在與RDS PostgreSQL同地區、同VPC下的ECS中進行測試。

  1. 使用一個隨機向量,與vtest表中的資料進行相似性比對,擷取比對結果中最相似的50條記錄。

    您需要建立一個sql檔案,然後寫入如下內容,用於後續壓測時使用。

    WITH tmp AS (
        SELECT random_array(1536)::VECTOR(1536) AS vec
    )
    SELECT id
    FROM vtest
    ORDER BY v <=> (SELECT vec FROM tmp)
    LIMIT FLOOR(RANDOM() * 50);
  2. 使用pgbench進行壓測。

    如下命令需要在命令列視窗執行,請確保已安裝PostgreSQL用戶端(本樣本以15.1為例),pgbench是在PostgreSQL上運行基準測試的簡單程式。該命令的更多用法,請參見PostgreSQL官方文檔

    pgbench -f ./test.sql -c6 -T60 -P5 -U testuser -h pgm-bp****.pg.rds.aliyuncs.com -p 5432 -d testdb

    各參數及說明如下:

    參數/取值

    說明

    -f ./test.sql

    指定測試指令碼檔案的路徑和檔案名稱。./test.sql僅為樣本,您需要根據實際情況修改路徑及檔案名稱。

    -c6

    設定並發用戶端數。-c表示指定並發用戶端數,6表示本樣本指定了6個並發用戶端來執行測試。

    -T60

    設定測試時間。-T表示指定測試的已耗用時間,60表示本樣本指定測試將運行60秒。

    -P5

    設定指令碼參數。表示本樣本中每5秒顯示一次進程報告。

    -U testuser

    指定資料庫使用者。testuser需要替換為您的資料庫使用者名稱。

    -h pgm-bp****.pg.rds.aliyuncs.com

    指定RDS PostgreSQL執行個體的內網串連地址。

    -p 5432

    指定RDS PostgreSQL執行個體的內網連接埠。

    -d testdb

    指定串連的資料庫,本樣本以testdb為例。

測試結果

向量資料、索引資料佔用的儲存空間以及TPS與資料量之間的測試結果

資料量(單位:萬行)

table size(單位:MB)

index size(單位:MB)

Latency(單位:ms)

TPS(單位:個)

10

796

782

15.7

380

30

2388

2345

63

94

50

3979

3907

74

80

80

6367

6251

90

66

100

7958

7813

105

56

lists固定時probes對查詢效率以及召回率的影響

當lists固定為2000,表中資料量為100萬行時,probes越大召回率越高,TPS越低。

image..png

probes固定時lists對查詢效率以及召回率的影響

當probes固定為20,表中資料量為100萬行時,lists越大,召回率越低,TPS越高

image..png

測試結論

  • lists的值對索引佔用的儲存空間影響微乎其微,和表中的資料量有直接的關係。

  • lists和probes對查詢效率以及召回率起著相反的作用,因此合理地設定這兩個值可以在查詢效率以及召回率上達到一個平衡。

    image..png

    根據表中行數(rows)的不同,建議設定的lists和probes值如下:

    • 小於等於100萬行:lists = rows / 1000probes = lists / 10

    • 大於100萬行:lists = sqrt(rows)probes = sqrt(lists)

      說明

      sqrt表示開方運算。

最佳實務

基於RDS PostgreSQL構建由LLM驅動的專屬ChatBot