調整向量查詢效能

選取說明文件版本:

本文將說明如何調整索引,以加快查詢速度並提升搜尋結果的相關性。

調整 ScaNN 索引

ScaNN 索引會使用以樹狀結構量化為基礎的索引。在樹狀結構量化技術中,索引會與量化 (或雜湊) 函式一起學習搜尋樹狀結構。執行查詢時,搜尋樹會用於剪除搜尋空間,而量化則用於壓縮索引大小。這項修剪作業可加快查詢向量與資料庫向量之間相似度 (即距離) 的評分速度。

如要透過最鄰近查詢達到高每秒查詢次數 (QPS) 和高召回率,您必須以最適合資料和查詢的方式,分割 ScaNN 索引的樹狀結構。

建立 ScaNN 索引前,請先完成下列步驟:

  • 確認已建立含有資料的表格。
  • 請確認為 maintenance_work_memshared_buffers 旗標設定的值小於機器總記憶體,以免在產生索引時發生問題。

調整參數

下列索引參數和資料庫標記會一併使用,以找出合適的召回率和 QPS 平衡點。所有參數都適用於兩種 ScaNN 索引類型。

調整參數 說明 參數類型
num_leaves 要套用至這個索引的分區數量。建立索引時套用的分區數量會影響索引效能。增加一組向量的分區數量,即可建立更精細的索引,進而提升召回率和查詢效能。不過,這樣會導致索引建立時間變長。

由於三層樹狀結構的建構速度比兩層樹狀結構快,因此建立三層樹狀結構索引時,您可以增加 num_leaves_value 來提升效能。
  • 雙層索引:將這個值設為 11048576 之間的任何值。

    如果不確定要選取哪個確切值,請以 sqrt(ROWS) 做為起點,其中 ROWS 是向量列數。每個分區所含的向量數量會以
    ROWS/sqrt(ROWS) = sqrt(ROWS).

    計算。由於可以在向量列數少於 1 千萬的資料集上建立雙層樹狀結構索引,因此每個分區所含的向量會少於 (sqrt(10M)) 個,也就是 3200 個向量。為獲得最佳效能,建議盡量減少每個分割區中的向量數量。
  • 三層索引:將這個值設為 11048576 之間的任何值。

    如果不確定要選取哪個確切值,請使用 power(ROWS, 2/3) 做為起點,其中 ROWS 是向量列數。每個分區所含的向量數量會由
    ROWS/power(ROWS, 2/3) = power(ROWS, 1/3).

    計算。由於可以在向量列超過 1 億的資料集上建立三層樹狀索引,因此每個分區會包含超過
    (power(100M, 1/3)) 個向量,也就是 465 個向量。為獲得最佳效能,建議盡量減少每個分割區中的向量數量。
建立索引
quantizer 您想用於 K 平均值樹狀結構的量化器類型。預設值為 SQ8,可提升查詢效能。

如要提升召回率,請將值設為 FLAT
建立索引
enable_pca 啟用主成分分析 (PCA),這是一種降維技術,可盡可能自動縮減嵌入的大小。這個選項預設為啟用。

如果發現召回率下降,請設為 false
建立索引
scann.num_leaves_to_search 資料庫旗標可控制喚回率和 QPS 之間的取捨。預設值為 num_leaves 中設定值的 1%。

設定的值越高,喚回度就越好,但 QPS 會降低,反之亦然。
查詢執行階段
scann.max_top_neighbors_buffer_size 資料庫標記會指定快取大小,用於在記憶體中評分或排序掃描的候選鄰項,而非在磁碟中,藉此提升篩選查詢的效能。預設值為 20000

設定的值越高,篩選查詢的 QPS 就越好,但記憶體用量也會增加,反之亦然。
查詢執行階段
scann.pre_reordering_num_neighbors 設定資料庫標記後,系統會在初始搜尋找出候選項目後,於重新排序階段考慮指定數量的候選鄰點。請將這個值設為大於查詢要傳回的鄰點數量。

較高的值集可提高喚回度,但這種做法會降低 QPS。
查詢執行階段
max_num_levels K-means 分群樹狀結構的層級數量上限。
  • 兩層樹狀結構索引:預設為兩層樹狀結構量化。
  • 三層樹狀結構索引:明確設為 2,以進行三層樹狀結構量化。
建立索引

調整 ScaNN 索引

請參閱以下兩層和三層 ScaNN 索引的範例,瞭解如何設定微調參數:

兩層索引

SET LOCAL scann.num_leaves_to_search = 1;
SET LOCAL scann.pre_reordering_num_neighbors=50;

CREATE INDEX my-scann-index ON my-table
  USING scann (vector_column cosine)
  WITH (num_leaves = [power(1000000, 1/2)]);

三層索引

SET LOCAL scann.num_leaves_to_search = 10;
SET LOCAL scann.pre_reordering_num_neighbors=50;

CREATE INDEX my-scann-index ON my-table
  USING scann (vector_column cosine)
  WITH (num_leaves = [power(1000000, 2/3)], max_num_levels = 2);

如果資料表已產生 ScaNN 索引,任何插入或更新作業都會影響學習樹狀結構最佳化索引的方式。如果表格經常更新或插入資料,建議您定期重新建立現有 ScaNN 索引,以提高召回準確度。

您可以監控索引指標,判斷自建立索引以來產生的變動量,然後據此重新建立索引。如要進一步瞭解指標,請參閱「向量索引指標」。

微調的最佳做法

根據您打算使用的ScaNN索引類型,調整索引的建議也會有所不同。本節提供相關建議,說明如何調整索引參數,在召回率和每秒查詢次數之間取得最佳平衡。

兩層樹狀結構索引

如要套用建議,協助您找出資料集的最佳 num_leavesnum_leaves_to_search 值,請按照下列步驟操作:

  1. 建立 ScaNN 索引,並將 num_leaves 設為索引資料表列數的平方根。
  2. 執行測試查詢,並提高 scann.num_of_leaves_to_search 的值,直到達到目標召回率範圍 (例如 95%) 為止。如要進一步瞭解如何分析查詢,請參閱「分析查詢」。
  3. 請記下 scann.num_leaves_to_searchnum_leaves 之間的比例,後續步驟會用到。這個比率會提供資料集近似值,協助您達成目標召回率。

    如果您使用高維度向量 (500 個以上的維度),並想提高召回率,請嘗試調整 scann.pre_reordering_num_neighbors 的值。首先,請將值設為 100 * sqrt(K),其中 K 是您在查詢中設定的限制。
  4. 如果查詢達到目標召回率後,QPS 仍過低,請按照下列步驟操作:
    1. 重新建立索引,並根據下列指引增加 num_leavesscann.num_leaves_to_search 的值:
      • num_leaves 設為大於列數平方根的因數。舉例來說,如果索引的 num_leaves 設為資料列數的平方根,請嘗試將其設為平方根的兩倍。如果值已是兩倍,請嘗試將值設為平方根的三倍。
      • 視需要增加 scann.num_leaves_to_search,以維持與 num_leaves 的比例 (您在步驟 3 中記下)。
      • num_leaves 設為小於或等於資料列數除以 100 的值。
    2. 再次執行測試查詢。 執行測試查詢時,請嘗試降低 scann.num_leaves_to_search,找出可提高每秒查詢次數,同時維持高召回率的值。嘗試使用不同的 scann.num_leaves_to_search 值,不必重建索引。
  5. 重複步驟 4,直到 QPS 和召回範圍都達到可接受的值。

三層樹狀結構索引

除了兩層樹狀結構 ScaNN 索引的建議做法外,請使用下列指引和步驟調整索引:

  • 將兩層樹狀結構的 max_num_levels1 增加到三層樹狀結構的 2,可大幅縮短建立索引的時間,但會降低召回準確度。請根據下列建議設定 max_num_levels
    • 如果向量資料列數超過 1 億列,請將值設為 2
    • 如果向量資料列數少於 1 千萬列,請將值設為 1
    • 如果向量列數介於 1 千萬到 1 億列之間,請根據索引建立時間和所需回想準確度的平衡,將值設為 12

如要套用建議,找出 num_leavesmax_num_levels 索引參數的最佳值,請按照下列步驟操作:

  1. 根據資料集建立 ScaNN 索引,並使用下列 num_leavesmax_num_levels 組合:

    • 向量資料列超過 1 億列:將 max_num_levels 設為 2,並將 num_leaves 設為 power(rows, ⅔)
    • 向量資料列少於 1 億列:將 max_num_levels 設為 1,並將 num_leaves 設為 sqrt(rows)
    • 向量資料列介於 1 千萬到 1 億列之間:請先將 max_num_levels 設為 1,並將 num_leaves 設為 sqrt(rows)
  2. 執行測試查詢。如要進一步瞭解如何分析查詢,請參閱「分析查詢」。

    如果索引建立時間令人滿意,請保留 max_num_levels 值,並試用 num_leaves 值,以達到最佳的召回準確度。

  3. 如果對索引建立時間不滿意,請執行下列操作:

    • 如果 max_num_levels 值為 1,請捨棄索引。將 max_num_levels 值設為 2,然後重建索引。

      執行查詢並調整 num_leaves 值,以獲得最佳的召回準確度。

    • 如果 max_num_levels 值為 2,請捨棄索引。使用相同的 max_num_levels 值重建索引,並調整 num_leaves 值,以達到最佳的召回準確度。

調整 IVF 索引

調整為 listsivf.probesquantizer 參數設定的值,可能有助於提升應用程式效能:

調整參數 說明 參數類型
lists 建立索引期間建立的清單數量。如要設定這個值,最多一百萬列的資料應從 (rows)/1000 開始,超過一百萬列的資料則應從 sqrt(rows) 開始。 建立索引
quantizer 您想用於 K 平均值樹狀結構的量化器類型。預設值為 SQ8,可提升查詢效能。設為 FLAT 可提高回想率。 建立索引
ivf.probes 搜尋期間要探索的最近清單數量。這個值的起點是
sqrt(lists)
查詢執行階段

請參考以下範例,瞭解如何設定調整參數的 IVF 索引:

SET LOCAL ivf.probes = 10;

CREATE INDEX my-ivf-index ON my-table
  USING ivf (vector_column cosine)
  WITH (lists = 100, quantizer = 'SQ8');

調整 IVFFlat 索引

調整為 listsivfflat.probes 參數設定的值,有助於提升應用程式效能:

調整參數 說明 參數類型
lists 建立索引期間建立的清單數量。如要設定這個值,最多一百萬列的資料應從 (rows)/1000 開始,超過一百萬列的資料則應從 sqrt(rows) 開始。 建立索引
ivfflat.probes 搜尋期間要探索的最近清單數量。這個值的起點是
sqrt(lists)
查詢執行階段

建立 IVFFlat 索引前,請確認資料庫的 max_parallel_maintenance_workers 旗標已設為足夠的值,可加快大型資料表的索引建立速度。

請參考以下範例,瞭解如何設定調整參數的 IVFFlat 索引:

SET LOCAL ivfflat.probes = 10;

CREATE INDEX my-ivfflat-index ON my-table
  USING ivfflat (vector_column cosine)
  WITH (lists = 100);

調整 HNSW 索引

調整為 mef_constructionhnsw.ef_search 參數設定的值,有助於提升應用程式效能。

調整參數 說明 參數類型
m 圖表中每個節點的連線數量上限。您可以從預設值 16(預設) 開始,並根據資料集大小嘗試使用較高的值。 建立索引
ef_construction 圖表建構期間維護的動態候選清單大小,會不斷更新節點的最近鄰項目前最佳候選項目。將這個值設為大於 m 值的兩倍,例如 64(預設值)。 建立索引
ef_search 搜尋期間使用的動態候選名單大小。您可以先將這個值設為 mef_construction,然後在觀察召回率時變更這個值。預設值為 40 查詢執行階段

請參考以下範例,瞭解如何設定調整參數的 hnsw 索引:

SET LOCAL hnsw.ef_search = 40;

CREATE INDEX my-hnsw-index ON my-table
  USING hnsw (vector_column cosine)
  WITH (m = 16, ef_construction = 200);

分析查詢

使用 EXPLAIN ANALYZE 指令分析查詢洞察,如下列 SQL 查詢範例所示。

  EXPLAIN ANALYZE SELECT result-column FROM my-table
    ORDER BY EMBEDDING_COLUMN ::vector
    USING INDEX my-scann-index
    <-> embedding('textembedding-gecko@003', 'What is a database?')
    LIMIT 1;

範例回應 QUERY PLAN 包含所花時間、掃描或傳回的資料列數,以及使用的資源等資訊。

Limit  (cost=0.42..15.27 rows=1 width=32) (actual time=0.106..0.132 rows=1 loops=1)
  ->  Index Scan using my-scann-index on my-table  (cost=0.42..858027.93 rows=100000 width=32) (actual time=0.105..0.129 rows=1 loops=1)
        Order By: (embedding_column <-> embedding('textgecko@003', 'What is a database?')::vector(768))
        Limit value: 1
Planning Time: 0.354 ms
Execution Time: 0.141 ms

查看向量索引指標

您可以運用向量索引指標查看向量索引的成效、找出需要改進的地方,並視需要根據指標調整索引。

如要查看所有向量索引指標,請執行下列 SQL 查詢 (使用 pg_stat_ann_indexes 檢視區塊):

SELECT * FROM pg_stat_ann_indexes;

如要進一步瞭解完整的指標清單,請參閱「向量索引指標」。

後續步驟