在處理大型數據集或需要快速訪問和檢索數據的場景(數據庫查詢優化、機器學習和數據挖掘、圖像和視頻檢索、空間數據查詢等)中,創建向量索引是加速向量檢索的有效方式,可以提高查詢性能、加速數據分析和優化搜索任務,從而提高系統的效率和響應速度。
背景信息
云原生數據倉庫AnalyticDB PostgreSQL版向量數據庫中的FastANN向量檢索引擎實現了主流的HNSW(Hierarchical Small World Graph)算法,它基于PostgreSQL中的段頁式存儲實現,并且在索引中只存儲了指向表中向量列的指針,極大地減少了向量索引的存儲空間。同時FastANN向量檢索引擎也支持PQ(Product Quantization)量化功能,可以對高維向量進行降維。通過在索引中存儲降維后的向量達到減少在向量插入和查詢時的回表操作,從而提升了向量檢索的性能。
語法
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>);
各字段說明:
INDEX_NAME:索引名。
SCHEMA_NAME:模式(命名空間)名。
TABLE_NAME:表名。
COLUMN_NAME:向量索引列名。
其他向量索引參數:
向量索引參數
是否必填
說明
默認值
取值范圍
DIM
是
向量維度。該參數主要用于向量插入時的檢查,當維度不匹配的時候,系統將提示相關錯誤信息。
0
[1, 8192]
DISTANCEMEASURE
否
支持的相似度距離度量算法:
L2:使用歐氏距離(平方)函數構建索引,通常適用于圖片相似度檢索場景。
計算公式:
IP:使用反內積距離函數構建索引,通常適用于向量歸一化之后替代余弦相似度。
計算公式:
COSINE:使用余弦距離函數構建索引,通常適用于文本相似度檢索場景。
計算公式:
L2
(L2, IP, COSINE)
HNSW_M
否
HNSW算法中的最大鄰居數。
32
[10, 1000]
HNSW_EF_CONSTRUCTION
否
HNSW算法構建索引時的候選集大小。
600
[40, 4000]
PQ_ENABLE
否
是否開啟PQ向量降維的功能。PQ向量降維依賴于存量的向量樣本數據進行訓練,如果數據量小于50w時,不建議設置此參數。
0
[0, 1]
PQ_SEGMENTS
否
PQ_ENABLE為1時生效。用于指定PQ向量降維過程中使用的kmeans聚類算法中的分段數。
如果DIM能被8整除,則不需要填寫,否則需要手動設置。
PQ_SEGMENTS必須大于0,且DIM必須能被PQ_SEGMENTS整除。
0
[1, 256]
PQ_CENTERS
否
PQ_ENABLE為1時生效。用于指定PQ向量降維過程中使用的kmeans聚類算法中的中心點數。
2048
[256, 8192]
EXTERNAL_STORAGE
否
是否使用mmap構建HNSW索引。
為0時,默認會采用段頁式存儲構建索引,這種模式可以使用PostgreSQL中的shared_buffer做緩存,支持刪除和更新等操作。
為1時,該索引會采用mmap構建索引,從v6.6.2.3版本開始為索引支持了標記刪除能力,可以支持數據表少量的刪除和更新操作。
0
[0, 1]
示例
假設有一個文本知識庫,將文章分割成chunk后,轉換為embedding向量,最后存入數據庫中,其中切割生成的chunks表包含以下字段:
字段 | 類型 | 說明 |
id | serial | 編號。 |
chunk | varchar(1024) | 文章切塊后的文本chunk。 |
intime | timestamp | 文章的入庫時間。 |
url | varchar(1024) | 文本chunk所屬文章的鏈接。 |
feature | real[] | 文本chunk embedding向量。 |
創建存儲向量的數據庫表。
CREATE TABLE chunks ( id SERIAL PRIMARY KEY, chunk VARCHAR(1024), intime TIMESTAMP, url VARCHAR(1024), feature REAL[] ) DISTRIBUTED BY (id);
將向量列的存儲模式設置為PLAIN,以降低數據行掃描成本,獲得更好的性能。
ALTER TABLE chunks ALTER COLUMN feature SET STORAGE PLAIN;
對向量列建立向量索引。
-- 創建歐氏距離度量的向量索引。 CREATE INDEX idx_chunks_feature_l2 ON chunks USING ann(feature) WITH (dim=1536, distancemeasure=l2, hnsw_m=64, pq_enable=1); -- 創建內積距離度量的向量索引。 CREATE INDEX idx_chunks_feature_ip ON chunks USING ann(feature) WITH (dim=1536, distancemeasure=ip, hnsw_m=64, pq_enable=1); -- 創建余弦相似度度量的向量索引。 CREATE INDEX idx_chunks_feature_cosine ON chunks USING ann(feature) WITH (dim=1536, distancemeasure=cosine, hnsw_m=64, pq_enable=1);
說明目前一個向量表可以創建多個向量列,每個向量列又可以創建多個向量索引,具體根據實際需要創建對應的向量索引,避免創建無效的索引。
向量查詢的方式必須與向量索引的距離度量對應。例如,向量查詢中的符號
<->
對應歐氏距離度量的向量索引,<#>
對應內積距離度量的向量索引,<=>
對應余弦相似度度量的向量索引。如果沒有對應的向量索引,則向量查詢會退化為精確搜索(即暴力搜索)。請使用FastANN向量檢索插件提供的
ANN
訪問方法,當實例開啟向量檢索引擎優化功能時,會自動在該實例中創建FastANN向量檢索插件。若報錯
You must specify an operator class or define a default operator class for the data type
,表示該實例未開啟向量檢索引擎優化功能,請開啟后重試,具體操作請參見開啟或關閉向量檢索引擎優化。
為常用的結構化列建立索引,提升融合查詢速度。
CREATE INDEX ON chunks(intime);
向量索引的構建方式
向量索引主要分為兩種構建方式:
流式構建。
即先創建一個空表,并在空表上建立向量索引,那么在進行向量數據導入時,就會進行流式實時的索引構建。此方式適用于實時向量檢索場景,但是會導致數據導入速度過慢。
異步構建。
即在創建一個空表后,在不建向量索引的情況下,先將數據導入,然后再對存量的向量數據構建向量索引。此方式適用于大規模向量數據導入的場景。
云原生數據倉庫AnalyticDB PostgreSQL版對于異步向量索引構建模式提供了并發構建能力,可以通過GUC參數fastann.build_parallel_processes來設置并行構建索引的并發度。
例如,在DMS上異步構建索引可以采用如下方式:
-- 假設在8C32GB的實例規格上進行操作。
-- 設置statement_timeout和idle_in_transaction_session_timeout都為0,確保不觸發超時中斷。
-- 設置fastann.build_parallel_processes為8,確保計算節點的CPU可以用滿,這里需要根據segment的不同的規格需要設置不同的值,如4C16GB的規格設置為4,8C32GB的規格設置為8,16C64GB規格設置為16。
-- 在DMS上,參數設置必須和索引創建的SQL在同一行,否則不能生效。
SET statement_timeout = 0;SET idle_in_transaction_session_timeout = 0;SET fastann.build_parallel_processes = 8;CREATE INDEX ON chunks USING ann(feature)
WITH (dim=1536, distancemeasure=cosine, hnsw_m=64, pq_enable=1);
使用psql進行異步構建索引時可以采用如下方式:
-- 假定和上面DMS操作的實例一樣,也是8C32GB的實例上進行操作。
-- 第一步:將以下內容放到文件create_index.sql中。
SET statement_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET fastann.build_parallel_processes = 8;
CREATE INDEX ON chunks USING ann(feature) WITH (dim=1536, distancemeasure=cosine, hnsw_m=64, pq_enable=1);
-- 第二步:執行如下命令開始并行構建索引。
psql -h gp-xxxx-master.gpdb.rds.aliyuncs.com -p 5432 -d dbname -U username -f create_index.sql
如果當前實例有業務正在使用,不能將索引構建的并行進程數調到和實例規格一致,否則會影響正在運行的業務。
相關參考
函數作用 | 向量函數 | 返回值類型 | 含義 | 支持數據類型 |
計算 | l2_distance | double precision | 歐氏距離(開方值),用于衡量兩個向量的大小,表示兩個向量的距離。普遍應用于檢索圖片相似度。 重要 l2_distance在V6.3.10.17及以下版本中為歐氏距離(平方值),在V6.3.10.18及以上版本中為歐式距離(開方值)。 | smallint[]、float2[]、float4[]、real[] |
inner_product_distance | double precision | 內積距離,在向量歸一化之后等于余弦相似度,通常用于在向量歸一化之后替代余弦相似度。 計算公式: | smallint[]、float2[]、float4[]、real[] | |
cosine_similarity | double precision | 余弦相似度,取值范圍:[-1, 1],通常用于衡量兩個向量在方向上的相似性,而不關心兩個向量的實際長度。 計算公式: | smallint[]、float2[]、float4[]、real[] | |
dp_distance | double precision | 點積距離,和內積距離完全一致。 計算公式: | smallint[]、float2[]、float4[]、real[] | |
hm_distance | integer | 漢明距離。 計算公式:位運算 | int[] | |
vector_add | smallint[], float2[] 或 float4[] | 計算兩個向量數組的加法。 | smallint[]、float2[]、float4[]、real[] | |
vector_sub | smallint[], float2[] 或 float4[] | 計算兩個向量數組的減法。 | smallint[]、float2[]、float4[]、real[] | |
vector_mul | smallint[], float2[] 或 float4[] | 計算兩個向量數組的乘法。 | smallint[]、float2[]、float4[]、real[] | |
vector_div | smallint[], float2[] 或 float4[] | 計算兩個向量數組的除法。 | smallint[]、float2[]、float4[]、real[] | |
vector_sum | int 或 double precision | 計算一個向量數組中所有元素的累加值。 | smallint[]、int[]、float2[]、float4[]、real[]、float8[] | |
vector_min | int 或 double precision | 統計一個向量數組中所有元素的最小值。 | smallint[]、int[]、float2[]、float4[]、real[]、float8[] | |
vector_max | int 或 double precision | 統計一個向量數組中所有元素的最大值。 | smallint[]、int[]、float2[]、float4[]、real[]、float8[] | |
vector_avg | int 或 double precision | 計算一個向量數組中所有元素的平均值。 | smallint[]、int[]、float2[]、float4[]、real[]、float8[] | |
vector_norm | double precision | 計算一個向量數組的模長。 | smallint[]、int[]、float2[]、float4[]、real[]、float8[] | |
vector_angle | double precision | 計算兩個向量數組的夾角。 | smallint[]、float2[]、float4[]、real[] | |
排序 | l2_squared_distance | double precision | 歐氏距離(平方值),由于比歐氏距離(開方值)少了開方的計算,因此主要用于對歐氏距離(開方值)的排序邏輯,以減少計算量。 計算公式: | smallint[]、float2[]、float4[]、real[] |
negative_inner_product_distance | double precision | 反內積距離,為內積距離取反后的結果,主要用于對內積距離的排序邏輯,以保證排序結果按內積距離從大到小排序。 計算公式: | smallint[]、float2[]、float4[]、real[] | |
cosine_distance | double precision | 余弦距離,取值范圍:[0, 2],主要用于對余弦相似度的排序邏輯,以保證排序結果按余弦相似度從大到小排序。 計算公式: | smallint[]、 float2[]、float4[]、real[] |
vector_add、vector_sub、vector_mul、vector_div、vector_sum、vector_min、vector_max、vector_avg、vector_norm和vector_angle向量函數僅v6.6.1.0及以上版本支持。如何查看實例版本,請參見查看內核小版本。
向量函數的使用示例:
-- 歐氏距離
SELECT l2_distance(array[1,1,1,1]::real[], array[2,2,2,2]::real[]);
-- 內積距離
SELECT inner_product_distance(array[1,1,1,1]::real[], array[2,2,2,2]::real[]);
-- 余弦相似度
SELECT cosine_similarity(array[1,1,1,1]::real[], array[2,2,2,2]::real[]);
-- 點積距離
SELECT dp_distance(array[1,1,1,1]::real[], array[2,2,2,2]::real[]);
-- 漢明距離
SELECT hm_distance(array[1,0,1,0]::int[], array[0,1,0,1]::int[]);
-- 向量數組加法
SELECT vector_add(array[1,1,1,1]::real[], array[2,2,2,2]::real[]);
-- 向量數組減法
SELECT vector_sub(array[1,1,1,1]::real[], array[2,2,2,2]::real[]);
-- 向量數組乘法
SELECT vector_mul(array[1,1,1,1]::real[], array[2,2,2,2]::real[]);
-- 向量數組除法
SELECT vector_div(array[1,1,1,1]::real[], array[2,2,2,2]::real[]);
-- 向量數組累加值
SELECT vector_sum(array[1,1,1,1]::real[]);
-- 向量數組最小值
SELECT vector_min(array[1,1,1,1]::real[]);
-- 向量數組最大值
SELECT vector_max(array[1,1,1,1]::real[]);
-- 向量數組平均值
SELECT vector_avg(array[1,1,1,1]::real[]);
-- 向量數組模長
SELECT vector_norm(array[1,1,1,1]::real[]);
-- 兩個向量的夾角
SELECT vector_angle(array[1,1,1,1]::real[], array[2,2,2,2]::real[]);
向量操作符 | 計算含義 | 排序含義 | 支持的數據類型 |
<-> | 獲取歐氏距離(平方),結果等同于l2_squared_distance。 | 按歐氏距離(平方)從小到大排序。 | smallint[]、float2[]、float4[]、real[] |
<#> | 獲取反內積,結果等同于negative_inner_product_distance。 | 按點積距離從大到小排序。 | smallint[]、float2[]、float4[]、real[] |
<=> | 獲取余弦距離,結果等同于cosine_distance。 | 按余弦相似度從大到小排序。 | smallint[]、float2[]、float4[]、real[] |
+ | 計算兩個向量的加法。 | 無 | smallint[]、float2[]、float4[]、real[] |
- | 計算兩個向量的減法。 | 無 | smallint[]、float2[]、float4[]、real[] |
* | 計算兩個向量的乘法。 | 無 | smallint[]、float2[]、float4[]、real[] |
/ | 計算兩個向量的除法。 | 無 | smallint[]、float2[]、float4[]、real[] |
+
、-
、*
和/
向量操作符僅v6.6.1.0及以上版本支持。如何查看實例版本,請參見查看內核小版本。
向量操作符的使用示例:
-- 歐氏距離
SELECT array[1,1,1,1]::real[] <-> array[2,2,2,2]::real[] AS score;
-- 內積距離
SELECT array[1,1,1,1]::real[] <#> array[2,2,2,2]::real[] AS score;
-- 余弦距離
SELECT array[1,1,1,1]::real[] <=> array[2,2,2,2]::real[] AS score;
-- 加法
SELECT array[1,1,1,1]::real[] + array[2,2,2,2]::real[] AS value;
-- 減法
SELECT array[1,1,1,1]::real[] - array[2,2,2,2]::real[] AS value;
-- 乘法
SELECT array[1,1,1,1]::real[] * array[2,2,2,2]::real[] AS value;
-- 除法
SELECT array[1,1,1,1]::real[] / array[2,2,2,2]::real[] AS value;