ScaNN 索引是 Google 製作的樹狀結構量化索引,用於近似最鄰近搜尋。與 HNSW 相比,這項技術可縮短索引建構時間,並減少記憶體用量。此外,根據工作負載,與 HNSW 相比,它能提供更快的 QPS。
事前準備
開始建立索引前,請先完成下列必要條件。
將嵌入向量新增至 AlloyDB Omni 資料庫中的資料表。
如果您嘗試在空白或分區資料表上產生 ScaNN 索引,可能會遇到一些問題。如要進一步瞭解產生的錯誤,請參閱「排解 ScaNN 索引錯誤」。如要在空白或小型資料表上建立索引,請參閱「針對空白或近乎空白的資料表延後建立索引」。
已安裝「
vector」和「alloydb_scann」擴充功能:CREATE EXTENSION IF NOT EXISTS alloydb_scann CASCADE;安裝
alloydb_scann擴充功能後,系統會自動檢查是否已安裝vector擴充功能,如果沒有,系統會安裝該擴充功能。您不必另外手動安裝vector。如要建立四層 ScaNN 索引,請先為 AlloyDB Omni 執行個體啟用預先發布功能。如要啟用「預覽」功能,請選擇下列其中一種方法:
啟用
scann.enable_preview_features資料庫旗標。如要進一步瞭解如何設定資料庫旗標,請參閱「設定資料庫旗標」。
在工作階段或執行個體層級,將
scann.max_allowed_num_levels資料庫旗標設為3。如要在工作階段層級設定標記,請執行下列指令:SET scann.max_allowed_num_levels = 3;如要在執行個體層級設定標記,請使用
--database-flags欄位執行gcloud alloydb alloydb instances update。
建立自動調整的索引
自動調整的 ScaNN 索引可讓 AlloyDB Omni 管理及調整索引結構,簡化索引建立作業。如需精細控管索引調整作業,請建立手動調整的 ScaNN 索引。
您可以透過兩種方式最佳化自動調整的索引:
- (預設) 向量搜尋召回率和延遲時間,但索引建構時間較長
- 在索引建構時間和搜尋效能之間取得平衡
如要建立自動調整的 ScaNN 索引,請執行下列指令。
CREATE INDEX INDEX_NAME ON TABLE
USING scann (EMBEDDING_COLUMN DISTANCE_FUNCTION)
更改下列內容:
INDEX_NAME:要建立的索引名稱。例如,my_scann_index。索引名稱會在資料庫中共用。確認每個索引名稱在資料庫的每個資料表中都是唯一的。TABLE:要新增索引的資料表。EMBEDDING_COLUMN:儲存vector資料的資料欄。DISTANCE_FUNCTION: 要用於這個索引的距離函式。選擇下列其中一個選項:L2 距離:
l2點積:
dot_product餘弦距離:
cosine
這項指令會建立專為搜尋效能最佳化的 ScaNN 索引。如要變更這項設定,請執行下列指令:
CREATE INDEX INDEX_NAME ON TABLE
USING scann (EMBEDDING_COLUMN DISTANCE_FUNCTION)
WITH (MODE='AUTO',
OPTIMIZATION='OPTIMIZATION')
更改下列內容:
INDEX_NAME:要建立的索引名稱。例如,my_scann_index。索引名稱會在資料庫中共用。確認每個索引名稱在資料庫的每個資料表中都是唯一的。TABLE:要新增索引的資料表。EMBEDDING_COLUMN:儲存vector資料的資料欄。DISTANCE_FUNCTION: 要用於這個索引的距離函式。選擇下列其中一個選項:L2 距離:
l2點積:
dot_product餘弦距離:
cosine
(選用)
OPTIMIZATION: 設為下列其中一項:(預設)
SEARCH_OPTIMIZED:同時最佳化向量搜尋召回率和向量搜尋延遲時間,但索引建構時間會較長。BALANCED:平衡索引建構時間和搜尋效能。
如果設定
OPTIMIZATION,則必須一併提供MODE='AUTO'。
建立手動調整的索引
如果應用程式對回呼和索引建構時間有特定要求,您可以手動建立及調整 ScaNN 索引。
如要為含有儲存向量嵌入內容的資料欄手動建立 ScaNN 索引,請參閱下列指令。
兩層樹狀結構索引
CREATE INDEX INDEX_NAME ON TABLE USING scann (EMBEDDING_COLUMN DISTANCE_FUNCTION) WITH (mode='MANUAL', num_leaves=NUM_LEAVES_VALUE, quantizer=QUANTIZER);
-
INDEX_NAME:要建立的索引名稱。例如:my_scann_index。資料庫會共用索引名稱。請確保資料庫中每個資料表的索引名稱都不重複。 -
TABLE:要新增索引的資料表。 -
EMBEDDING_COLUMN:儲存 `vector` 資料的資料欄。 -
DISTANCE_FUNCTION:要用於這個索引的距離函式。選擇下列其中一個選項:- L2 距離:
l2 - 點積:
dot_product - 餘弦距離:
cosine
- L2 距離:
-
NUM_LEAVES_VALUE: 要套用至這個索引的分區數量。設定為介於 1 到 3,000 萬之間的任何值。如要進一步瞭解如何選擇這個值,請參閱「調整ScaNN索引」。 -
QUANTIZER:要使用的量化器類型。請注意,ScaNN 索引可以載入資料欄引擎,進一步加快向量搜尋速度。選擇下列其中一個選項:-
(預設)
SQ8:在查詢效能與召回率損失之間取得平衡。這通常不到 1 到 2%。 -
(預先發布版)
AH:與SQ8相比,非對稱式雜湊 (AH) 的壓縮率最高可達 4 倍。如果啟用資料欄引擎,且索引和表格資料已填入資料欄引擎,則查詢效能可能會更好。詳情請參閱「調整 ScaNN 的最佳做法」。 -
FLAT:提供最高召回率 (99% 以上),但會影響搜尋效能。
-
(預設)
三層樹狀結構索引
CREATE INDEX INDEX_NAME ON TABLE USING scann (EMBEDDING_COLUMN DISTANCE_FUNCTION) WITH (mode='MANUAL', num_leaves=NUM_LEAVES_VALUE, quantizer=QUANTIZER, max_num_levels = 2);
-
INDEX_NAME:要建立的索引名稱。例如:my_scann_index。資料庫會共用索引名稱。請確保資料庫中每個資料表的索引名稱都不重複。 -
TABLE:要新增索引的資料表。 -
EMBEDDING_COLUMN:儲存 `vector` 資料的資料欄。 -
DISTANCE_FUNCTION:要用於這個索引的距離函式。選擇下列其中一個選項:- L2 距離:
l2 - 點積:
dot_product - 餘弦距離:
cosine
- L2 距離:
-
NUM_LEAVES_VALUE: 要套用至這個索引的分區數量。設定為介於 1 到 3,000 萬之間的任何值。如要進一步瞭解如何選擇這個值,請參閱「調整ScaNN索引」。 -
QUANTIZER:要使用的量化器類型。請注意,ScaNN 索引可以載入資料欄引擎,進一步加快向量搜尋速度。選擇下列其中一個選項:-
(預設)
SQ8:在查詢效能與召回率損失之間取得平衡。這通常不到 1 到 2%。 -
(預先發布版)
AH:與SQ8相比,非對稱式雜湊 (AH) 的壓縮率最高可達 4 倍。如果啟用資料欄引擎,且索引和表格資料已填入資料欄引擎,則查詢效能可能會更好。詳情請參閱「調整 ScaNN 的最佳做法」。 -
FLAT:提供最高召回率 (99% 以上),但會影響搜尋效能。
-
(預設)
-
max_num_levels = 2:K 平均叢集樹狀結構的質心層級數量上限。將這個參數設為2,即可建立三層索引。
四層樹狀結構索引
CREATE INDEX INDEX_NAME ON TABLE USING scann (EMBEDDING_COLUMN DISTANCE_FUNCTION) WITH (mode='MANUAL', num_leaves=NUM_LEAVES_VALUE, quantizer=QUANTIZER, max_num_levels = 3);
-
INDEX_NAME:要建立的索引名稱。例如:my_scann_index。資料庫會共用索引名稱。請確保資料庫中每個資料表的索引名稱都不重複。 -
TABLE:要新增索引的資料表。 -
EMBEDDING_COLUMN:儲存 `vector` 資料的資料欄。 -
DISTANCE_FUNCTION:要用於這個索引的距離函式。選擇下列其中一個選項:- L2 距離:
l2 - 點積:
dot_product - 餘弦距離:
cosine
- L2 距離:
-
NUM_LEAVES_VALUE: 要套用至這個索引的分區數量。設定為介於 1 到 3,000 萬之間的任何值。如要進一步瞭解如何選擇這個值,請參閱「調整ScaNN索引」。 -
QUANTIZER:要使用的量化器類型。請注意,ScaNN 索引可以載入資料欄引擎,進一步加快向量搜尋速度。選擇下列其中一個選項:-
(預設)
SQ8:在查詢效能與召回率損失之間取得平衡。這通常不到 1 到 2%。 -
預先發布版
AH:與SQ8相比,非對稱雜湊 (AH) 最多可壓縮 4 倍。如果啟用資料欄引擎,且索引和表格資料已填入資料欄引擎,則查詢效能可能會更好。詳情請參閱「調整 ScaNN 的最佳做法」。 -
FLAT:提供最高召回率 (99% 以上),但會影響搜尋效能。
-
(預設)
-
max_num_levels = 3:K 平均叢集樹狀結構的質心層級數量上限。將這個參數設為3,即可建立四層索引。
將手動調整的索引轉換為自動調整的索引
如要將手動調整的索引轉換為自動調整的索引,請完成下列步驟:
重設為手動調整的索引定義的所有查詢參數。
ALTER INDEX INDEX_NAME RESET (PARAMETER_NAME);請替換下列變數:
INDEX_NAME:要轉換的索引名稱。例如,my_scann_index。資料庫會共用索引名稱。確認資料庫中每個資料表的索引名稱都不重複。PARAMETER_NAME:以半形逗號分隔的清單,內含要重設的查詢參數名稱。例如:num_leaves, quantization。請注意,您必須先重設所有其他查詢參數,才能重設
num_leaves。
重新建立手動調整的索引,將其轉換為自動調整的索引。
REINDEX INDEX CONCURRENTLY INDEX_NAME;
為 real[] 資料類型建立 ScaNN 索引
如要為使用 real[] 資料類型 (而非 vector) 的嵌入資料欄建立索引,請將資料欄轉換為 vector 資料類型:
CREATE INDEX INDEX_NAME ON TABLE
USING scann (CAST(EMBEDDING_COLUMN AS vector(DIMENSIONS)) DISTANCE_FUNCTION)
更改下列內容:
INDEX_NAME:要建立的索引名稱。例如,my_scann_index。索引名稱會在資料庫中共用。確認每個索引名稱在資料庫的每個資料表中都是唯一的。TABLE:要新增索引的資料表。DIMENSIONS:模型支援的維度數量。EMBEDDING_COLUMN:儲存vector資料的資料欄。DISTANCE_FUNCTION: 要用於這個索引的距離函式。選擇下列其中一個選項:L2 距離:
l2點積:
dot_product餘弦距離:
cosine
查看建立索引的進度
如要查看索引建立進度,請使用 pg_stat_progress_create_index 檢視畫面:
SELECT * FROM pg_stat_progress_create_index;
「狀態」phase欄會顯示索引建立作業的目前狀態。索引建構階段完成後,索引的資料列就不會顯示。
為空白資料表或資料列不足的資料表建立延後索引
根據預設,您無法在空白資料表或列數少於 num_leaves 索引選項值的資料表上建立 ScaNN 索引。
如要略過這項限制,請啟用延後建立索引功能,讓 AlloyDB Omni 延後建立索引,直到資料表中的資料列數量達到 num_leaves 定義的門檻為止。達到門檻後,AlloyDB Omni 就會在背景開始建構索引。
這項延遲作業屬於非封鎖程序,因此讀取和寫入等其他資料庫作業可繼續執行,不會中斷。由於索引重建作業會在背景執行,因此如果資料表是以小批次方式擷取資料列,就適合使用延後建立索引功能。當列數達到門檻時,系統會自動觸發索引重建作業。
不過,如果您打算在單一交易中將大量資料列插入資料表,建議您將交易分割為多筆交易,或產生 ScaNN 索引,但不要啟用延後建立索引。
啟用延後建立索引
如要啟用延後建立索引功能,請按照下列步驟操作:
確認已啟用
scann.enable_index_maintenance標記和下列其中一個標記:scann.enable_preview_features: 這個旗標也會啟用其他預覽功能。scann.enable_index_with_insufficient_data:這個旗標只會明確啟用延後建立索引功能。
如要設定用量,請使用
gcloudCLI:如要啟用延遲建立索引功能和其他預先發布版功能,請按照下列步驟操作:
gcloud alloydb instances update INSTANCE_ID \ --database-flags scann.enable_index_maintenance=on \ --database-flags scann.enable_preview_features=on \ --region=REGION_ID \ --cluster=CLUSTER_ID \ --project=PROJECT_ID如要明確啟用延後建立索引功能,但不要啟用其他搶先版功能,請執行下列步驟:
gcloud alloydb instances update INSTANCE_ID \ --database-flags scann.enable_index_maintenance=on \ --database-flags scann.enable_index_with_insufficient_data=on \ --region=REGION_ID \ --cluster=CLUSTER_ID \ --project=PROJECT_ID
更改下列內容:
INSTANCE_ID:執行個體的 ID。REGION_ID:執行個體所在的區域,例如us-central1。CLUSTER_ID:執行個體所在的叢集 ID。PROJECT_ID:叢集所在的專案 ID。
建立 ScaNN 索引。如果您在手動模式中建立索引,請確認
auto_maintenance參數已設為on。詳情請參閱「建立手動調整的索引」。
限制
- 自動建立索引的背景程序會使用資料庫層級的旗標值。即使您使用
SET LOCAL指令設定任何工作階段層級的旗標,程序仍會考量資料庫層級設定的旗標值。 - 如果您打算在單一交易中,將大量資料大量插入空白資料表,建議您執行單一插入交易,然後建立 ScaNN 索引。
強制在空白或小型資料表上建立索引
AlloyDB Omni 會使用驗證機制,防止在空白資料表或資料列極少的資料表上建立 ScaNN 索引,原因如下:
ScaNN 索引訓練的資料不足。這可能會導致向量相似度搜尋的召回率不佳。
寫入資料庫的效能可能會降低。
如果效能不佳,建議您延後建立索引。
不過,在某些開發或測試情境中,您可能需要在空白或小型資料表上建立索引。在這種情況下,您可以強制建立索引。請注意,強制建立索引需要 SUPERUSER 權限。
如要強制建立索引,請完成下列步驟:
在資料庫中,將
scann.allow_blocked_operations工作階段層級參數設為true:SET scann.allow_blocked_operations = true;如果您用來執行這些查詢的使用者沒有
SUPERUSER權限,請指派權限:CREATE USER USERNAME WITH SUPERUSER PASSWORD PASSWORD;請替換下列變數:
USERNAME:要授予SUPERUSER權限的使用者名稱。PASSWORD:使用者的密碼。
平行建構索引
為加快建立索引的速度,AlloyDB Omni 可能會視資料集和所選索引類型,自動產生多個平行工作站。建立三或四層 ScaNN 索引,或是資料集超過 1 億列時,通常會觸發這項錯誤。
雖然 AlloyDB Omni 會自動調整平行工作站數量,但您可以使用下列 PostgreSQL 查詢規劃參數調整平行工作站:
為避免建立 ScaNN 索引時發生記憶體不足的問題,請確保 maintenance_work_mem 和 shared_buffers 資料庫旗標的值小於機器總記憶體。
執行查詢
將嵌入內容儲存到資料庫並建立索引後,即可開始查詢資料。您無法使用 alloydb_scann 擴充功能執行大量搜尋查詢。
如要找出文字字串最接近的語意鄰近項目,可以使用 google_ml.embedding() 函式將文字轉換為向量。
由於 google_ml.embedding() 會傳回實際陣列,因此您必須先將函式呼叫明確轉換為 vector,再套用至其中一個最鄰近的鄰項運算子,例如 L2 距離的 <->。這些運算子隨後可以使用 ScaNN 索引,找出語意最相似的嵌入資料庫資料列。
SELECT * FROM TABLE
ORDER BY EMBEDDING_COLUMN DISTANCE_FUNCTION_QUERY
google_ml.embedding(
model_id => 'MODEL_ID',
content => 'CONTENT')::vector
LIMIT ROW_COUNT
請替換下列變數:
TABLE:包含要與文字比較的嵌入內容的資料表。EMBEDDING_COLUMN: 包含所儲存嵌入的資料欄。DISTANCE_FUNCTION_QUERY:要用於這項查詢的距離函式。建立索引時,請選擇距離函式的對等查詢:L2 距離:
<->內積:
<#>餘弦距離:
<=>
MODEL_ID:要使用的已註冊嵌入模型 ID。CONTENT:要翻譯成嵌入內容並搜尋的文字字串。ROW_COUNT:要傳回的資料列數。舉例來說,如要取得單一最佳結果,請指定1。