建立 ScaNN 索引

本頁說明如何使用儲存的嵌入項目產生索引,以及如何使用 ScaNN 索引查詢 AlloyDB for PostgreSQL 的嵌入項目。如要進一步瞭解如何儲存嵌入內容,請參閱「儲存向量嵌入內容」。

AlloyDB alloydb_scann:Google 開發的 PostgreSQL 擴充功能,可實作由 ScaNN 演算法支援的高效率最鄰近索引。

ScaNN 索引是樹狀結構的量化索引,用於近似最近鄰搜尋。與 HNSW 相比,這項功能可縮短索引建構時間,並減少記憶體用量。此外,與 HNSW 相比,這項服務可根據工作負載提供更快的 QPS。

事前準備

開始建立索引前,請先完成下列必要條件。

  • 嵌入向量會新增至 AlloyDB 資料庫中的資料表

  • 系統會安裝以 pgvector 為基礎的 vector 擴充功能,這項擴充功能由 Google 擴充,適用於 AlloyDB,以及 alloydb_scann 擴充功能:

    CREATE EXTENSION IF NOT EXISTS alloydb_scann CASCADE;
    
  • 如要建立自動調整的 ScaNN 索引,請務必啟用 scann.enable_preview_features 標記。如不想啟用搶先體驗功能,或用於正式版例項,可以使用特定參數建立 ScaNN 索引

建立自動調整的 ScaNN 索引

使用自動建立索引功能,即可簡化索引建立程序,自動建立經過最佳化的索引,提升搜尋效能,或兼顧索引建立時間和搜尋效能。

使用 AUTO 模式時,您只需要指定資料表名稱和嵌入資料欄,以及要使用的距離函式。您可以針對搜尋效能最佳化索引,或在索引建構時間和搜尋效能之間取得平衡。

您也可以使用 MANUAL 模式建立索引,並精細控管其他索引調整參數。

在 AUTO 模式中建立 ScaNN 索引

AUTO 模式下建立索引前,請注意下列幾點:

  • 如果資料不足,AlloyDB 無法為資料表建立 ScaNN 索引。
  • AUTO 模式下建立索引時,無法設定索引建立參數,例如 num_leaves
  • AUTO 模式中建立的所有索引,預設都會啟用自動維護功能。

如要在 AUTO 模式中建立索引,請啟用 scann.enable_zero_knob_index_creation 功能旗標。這樣一來,系統就會自動維護。 啟用旗標後,請執行下列指令:

  CREATE INDEX INDEX_NAME ON TABLE
  USING scann (EMBEDDING_COLUMN DISTANCE_FUNCTION)
  WITH (mode='AUTO');

更改下列內容:

  • INDEX_NAME:要建立的索引名稱,例如 my-scann-index。資料庫會共用索引名稱。確認資料庫中每個資料表的索引名稱都不重複。

  • TABLE:要新增索引的資料表。

  • EMBEDDING_COLUMN:儲存 vector 資料的資料欄。

  • DISTANCE_FUNCTION:要搭配這個索引使用的距離函式。選擇下列其中一個選項:

    • L2 距離: l2

    • 點積: dot_product

    • 餘弦距離: cosine

  • OPTIMIZATION (選用):根據預設,系統會建立經過搜尋最佳化的索引。請設為下列其中一個值:

    • SEARCH_OPTIMIZED (預設):以較長的索引建構時間為代價,盡可能提升向量搜尋的召回率和縮短延遲時間。
    • BALANCED:建立索引,兼顧索引建構時間和搜尋效能。

在「MANUAL」模式中建立 ScaNN 索引

如果您已啟用 scann.enable_preview_features 旗標,且想進一步控管微調參數,可以在 MANUAL 模式中建立索引。

如要在 MANUAL 模式下建立 ScaNN 索引,請執行下列指令:

  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=MAX_NUM_LEVELS);

更改下列內容:

  • INDEX_NAME:要建立的索引名稱,例如 my-scann-index。資料庫會共用索引名稱。確認資料庫中每個資料表的索引名稱都不重複。

  • TABLE:要新增索引的資料表。

  • EMBEDDING_COLUMN:儲存 vector 資料的資料欄。

  • DISTANCE_FUNCTION:要搭配這個索引使用的距離函式。選擇下列其中一個選項:

    • L2 距離: l2

    • 點積: dot_product

    • 餘弦距離: cosine

  • NUM_LEAVES_VALUE:要套用至這個索引的分區數量。設定為介於 1 到 1 千萬之間的任何值。如要進一步瞭解如何選擇這個值,請參閱「調整 ScaNN 索引」。

  • QUANTIZER:要使用的量化器類型。可用選項如下:

    • SQ8:可兼顧查詢效能,並將召回率損失降到最低,通常低於 1% 到 2%。這是預設值。
    • AH:如果啟用資料欄引擎,且索引和表格資料已填入資料欄引擎 (視設定大小而定),建議使用這個選項,查詢效能可能會更好。請注意,與 SQ8 相比,AH 的壓縮率最高可達 4 倍。詳情請參閱「調整 ScaNN 的最佳做法」。
    • FLAT:提供 99% 以上的最高召回率,但會影響搜尋效能。
  • MAX_NUM_LEVELS:K 平均叢集樹狀結構的層級數量上限。設為 1(預設值) 可進行兩層樹狀結構量化,設為 2 則可進行三層樹狀結構量化。

您可以新增其他索引建立或查詢執行階段參數,調整索引。詳情請參閱「調整 ScaNN 索引」。

使用特定參數建立 ScaNN 索引

如果應用程式對回溯和索引建構時間有特定需求,可以手動建立索引。您可以根據工作負載建立兩層或三層樹狀結構索引。如要進一步瞭解如何調整參數,請參閱「調整 ScaNN 索引」。

兩層樹狀結構索引

如要使用 ScaNN 演算法,將兩層樹狀結構索引套用至含有已儲存向量嵌入的資料欄,請執行下列 DDL 查詢:

CREATE INDEX INDEX_NAME ON TABLE
USING scann (EMBEDDING_COLUMN DISTANCE_FUNCTION)
WITH (num_leaves=NUM_LEAVES_VALUE, quantizer =QUANTIZER);

更改下列內容:

  • INDEX_NAME:要建立的索引名稱,例如 my-scann-index。索引名稱會在資料庫中共用。請確保資料庫中每個資料表的索引名稱都不重複。

  • TABLE:要新增索引的資料表。

  • EMBEDDING_COLUMN:儲存 vector 資料的資料欄。

  • DISTANCE_FUNCTION:要搭配這個索引使用的距離函式。選擇下列其中一個選項:

    • L2 距離: l2

    • 點積: dot_product

    • 餘弦距離: cosine

  • NUM_LEAVES_VALUE:要套用至這個索引的分區數量。請設為介於 1 到 1 千萬之間的值。如要進一步瞭解如何選擇這個值,請參閱「調整 ScaNN 索引」。

  • QUANTIZER:要使用的量化器類型。可用選項如下:

    • SQ8:可兼顧查詢效能,並將召回率損失降至最低,通常低於 1% 至 2%。這是預設值。
    • AH:如果啟用資料欄引擎,且索引和表格資料已填入資料欄引擎 (視設定大小而定),則可考慮使用這個選項,以提升查詢效能。請注意,與 SQ8 相比,AH 的壓縮率最高可達 4 倍。詳情請參閱「調整 ScaNN 的最佳做法」。
    • FLAT:提供 99% 以上的最高召回率,但會影響搜尋效能。

三層樹狀結構索引

如要使用 ScaNN 演算法,為含有儲存向量嵌入的資料欄建立三層樹狀結構索引,請執行下列 DDL 查詢:

CREATE INDEX INDEX_NAME ON TABLE
  USING scann (EMBEDDING_COLUMN DISTANCE_FUNCTION)
  WITH (num_leaves=NUM_LEAVES_VALUE, max_num_levels = 2);

建立索引後,您可以按照「使用指定文字提出最鄰近查詢」一文中的操作說明,執行最鄰近搜尋查詢,藉此使用索引。

您必須設定索引參數,在 QPS 和召回率之間取得適當的平衡。如要進一步瞭解如何調整 ScaNN 索引,請參閱「調整 ScaNN 索引」。

如要在使用 real[] 資料類型 (而非 vector) 的嵌入資料欄上建立這個索引,請將該資料欄轉換為 vector 資料類型:

CREATE INDEX INDEX_NAME ON TABLE
USING scann (CAST(EMBEDDING_COLUMN AS vector(DIMENSIONS)) DISTANCE_FUNCTION)
WITH (num_leaves=NUM_LEAVES_VALUE, max_num_levels = MAX_NUM_LEVELS);

請將 DIMENSIONS 改成嵌入資料欄的維度寬度。如要進一步瞭解如何尋找維度,請參閱向量函式中的 vector_dims 函式。

如要確保搜尋體驗一致,請在建立 ScaNN 索引時啟用自動維護功能。詳情請參閱「維護向量索引」。這項功能目前為預先發布版

如要查看索引建立進度,請使用 pg_stat_progress_create_index 檢視畫面:

SELECT * FROM pg_stat_progress_create_index;

phase 欄會顯示索引建立作業的目前狀態。索引建構階段完成後,索引的資料列就不會顯示。

如要調整索引,以達到平均召回率和每秒查詢次數的平衡,請參閱「調整 ScaNN 索引」。

強制在空白或小型資料表上建立索引

AlloyDB 設有驗證機制,可防止在空白資料表或資料列極少的資料表上建立 ScaNN 索引,因為這可能會導致效能不佳。不過,在某些開發或測試情境中,您可能需要在空白或小型資料表上建立索引。在這些情況下,您可以強制建立索引。

如要強制產生索引,請完成下列步驟:

  1. 在資料庫中,將 scann.allow_blocked_operations creation 工作階段層級參數設為 true

    SET scann.allow_blocked_operations = true;
    
  2. SUPERUSER 權限指派給在資料庫中執行這些查詢的使用者:

    CREATE USER USER_NAME WITH SUPERUSER PASSWORD PASSWORD;
    

    更改下列內容:

    • USER_NAME:要授予權限的使用者名稱。
    • PASSWORD:使用者密碼。

並行建構索引

為加快建立索引的速度,AlloyDB 可能會視資料集和所選索引類型,自動產生多個平行工作站。

如果您要建立 3 層 ScaNN 索引,或資料集超過 1 億列,通常會觸發平行索引建構作業。

雖然 AlloyDB 會自動調整平行工作站數量,但您可以使用 max_parallel_maintenance_workersmax_parallel_workersmin_parallel_table_scan_size PostgreSQL 查詢規劃參數,調整平行工作站。

執行查詢

將嵌入內容儲存到資料庫並建立索引後,即可開始查詢資料。您無法使用 alloydb_scann 擴充功能執行大量搜尋查詢。

如要找出嵌入向量最鄰近的語意鄰居,可以執行下列查詢範例,並設定您在建立索引時使用的相同距離函式。

  SELECT * FROM TABLE
  ORDER BY EMBEDDING_COLUMN DISTANCE_FUNCTION_QUERY 'EMBEDDING'
  LIMIT ROW_COUNT

更改下列內容:

  • TABLE:包含要與文字比較的嵌入內容的資料表。

  • INDEX_NAME:要使用的索引名稱,例如 my-scann-index

  • EMBEDDING_COLUMN:包含儲存的嵌入內容的資料欄。

  • DISTANCE_FUNCTION_QUERY:要用於這項查詢的距離函式。根據建立索引時使用的距離函式,選擇下列其中一項:

    • L2 距離: <->

    • 內積: <#>

    • 餘弦距離: <=>

  • EMBEDDING:您要尋找最鄰近儲存語意鄰項的嵌入向量。

  • ROW_COUNT:要傳回的列數。

    如只要取得最佳單一比對結果,請指定 1

您也可以使用 embedding() 函式將文字翻譯成向量。由於 embedding() 會傳回 real 陣列,因此您必須先將 embedding() 呼叫明確轉換為 vector,才能套用至其中一個最鄰近的鄰域運算子 (例如 <->,適用於 L2 距離)。這些運算子隨後可以使用 ScaNN 索引,找出語意相似度最高的嵌入資料庫資料列。

後續步驟