使用分區 DML 為文字資料大量產生向量嵌入

本文說明如何使用 SQL 和 Gemini Enterprise Agent Platform 文字嵌入模型,為儲存在 Spanner 中的文字資料 (STRING 或 JSON) 大量生成及補充向量嵌入。

必要條件

Spanner 資料庫中必須有包含文字資料 (STRING 或 JSON) 的資料表。如要進一步瞭解如何匯入資料,請參閱「Spanner 匯入和匯出總覽」。

用途範例

假設 Spanner 中有一個資料表,結構定義如下。這個資料表含有數百萬筆記錄。

GoogleSQL

CREATE TABLE Products (
  product_id INT64 NOT NULL,
  name STRING(MAX),
  description STRING(MAX)
) PRIMARY KEY(product_id);

PostgreSQL

CREATE TABLE Products (
  product_id INT8 NOT NULL,
  name TEXT,
  description TEXT,
  PRIMARY KEY(product_id)
);

您的目標是為這個資料表的 description 欄生成向量嵌入,並使用向量搜尋找出類似商品,推薦給顧客,提升購物體驗。

註冊嵌入模型

GoogleSQL

在 Spanner 資料庫中,使用 Agent Platform 模型端點註冊文字嵌入模型:

CREATE MODEL MODEL_NAME
INPUT(
  content STRING(MAX)
)
OUTPUT(
  embeddings STRUCT<values ARRAY<FLOAT32>>
)
REMOTE OPTIONS(
    endpoint = '//aiplatform.googleapis.com/projects/PROJECT/locations/LOCATION/publishers/google/models/$MODEL_NAME',
  default_batch_size = 5
)

替換下列內容:

  • MODEL_NAME:Agent Platform 文字嵌入模型的名稱
  • PROJECT:託管 Agent Platform 端點的專案
  • LOCATION:Agent Platform 端點的位置

PostgreSQL

在 PostgreSQL 方言中,不需要註冊模型。您會將端點名稱直接傳遞至 spanner.ML_PREDICT_ROW 函式呼叫。

如要瞭解最佳做法,請參考下列事項:

  • 為維持配額隔離,請使用其他專案中的端點,生成及補充嵌入項目,而非實際工作環境端點。保留正式環境端點,用於提供正式環境流量。
  • 確認模型端點支援 default_batch_size 的值。您可以使用查詢提示 @{remote_udf_max_rows_per_rpc=NEW_NUMBER} 覆寫 default_batch_size。如要瞭解各區域的 default_batch_size 限制,請參閱「取得文字片段的文字嵌入」。
  • 請使用特定模型版本 (例如 @003) 定義端點,而非 @latest。這是因為同一段文字生成的嵌入向量,可能會因使用的模型版本而異,因此請避免使用不同模型版本在同一個資料集生成嵌入。此外,在模型定義陳述式中更新模型版本,並不會更新已使用這個模型生成的嵌入。如要管理嵌入的模型版本,其中一種方法是在資料表中建立額外的資料欄,用於儲存模型版本。
  • GoogleSQL ML.PREDICT 和 PostgreSQL spanner.ML_PREDICT_ROW 函式不支援自訂調整的文字嵌入模型。

測試嵌入模型的端對端整合

您可以執行查詢,測試嵌入模型是否設定成功,以及是否擷取嵌入。例如,執行下列查詢:

GoogleSQL

SELECT embeddings.values
FROM SAFE.ML.PREDICT(
  MODEL MODEL_NAME,
  (SELECT description AS content FROM products LIMIT 10)
);

替換下列內容:

  • MODEL_NAME:Agent Platform 文字嵌入模型的名稱

PostgreSQL

SELECT spanner.ML_PREDICT_ROW(
    'projects/PROJECT/locations/LOCATION/publishers/google/models/$MODEL_NAME',
    JSONB_BUILD_OBJECT('instances', JSONB_BUILD_ARRAY(JSONB_BUILD_OBJECT('content', description))))
FROM Products
LIMIT 10;

替換下列內容:

  • PROJECT:託管 Agent Platform 端點的專案
  • LOCATION:Agent Platform 端點的位置
  • MODEL_NAME:Agent Platform 文字嵌入模型的名稱

更新來源資料表,加入額外資料欄來儲存嵌入

接著,更新來源資料表結構定義,新增嵌入欄。儲存嵌入時,不一定要指定向量長度,但建議指定,以提升 KNN 搜尋效能。向量索引則必須指定向量長度。如果資料欄儲存不同維度的向量,請省略向量長度:

GoogleSQL

ALTER TABLE TABLE_NAME
ADD COLUMN EMBEDDING_COLUMN_NAME ARRAY<FLOAT32>(vector_length=>VECTOR_LENGTH);

替換下列內容:

  • TABLE_NAME:來源資料表的名稱
  • EMBEDDING_COLUMN_NAME:要新增生成嵌入的資料欄名稱
  • VECTOR_LENGTH:嵌入模型的輸出維度,例如 768 或 3072

PostgreSQL

ALTER TABLE TABLE_NAME
ADD COLUMN EMBEDDING_COLUMN_NAME real[] VECTOR LENGTH VECTOR_LENGTH;

替換下列內容:

  • TABLE_NAME:來源資料表的名稱
  • EMBEDDING_COLUMN_NAME:要新增生成嵌入的資料欄名稱
  • VECTOR_LENGTH:嵌入模型的輸出維度,例如 768 或 3072

舉例來說,使用 products 資料表示例,執行:

GoogleSQL

ALTER TABLE Products
ADD COLUMN desc_embed ARRAY<FLOAT32>(vector_length=>768);

PostgreSQL

ALTER TABLE Products
ADD COLUMN desc_embed real[] VECTOR LENGTH 768;

您可以新增其他資料欄,管理嵌入模型的版本。

GoogleSQL

ALTER TABLE Products
ADD COLUMN desc_embed_model_version INT64;

PostgreSQL

ALTER TABLE Products
ADD COLUMN desc_embed_model_version INT8;

提高 Agent Platform 的配額

您可能需要為使用文字嵌入模型的區域,提高 Agent Platform API 配額。如要申請提高配額,請參閱 Agent Platform 配額提高。

補充嵌入

最後,使用分區 DML 執行下列 UPDATE 陳述式,為文字資料欄生成嵌入,並將嵌入儲存在資料庫中。您可以將模型版本與嵌入項目一併儲存。建議您在資料庫流量較低時執行這項查詢。

GoogleSQL

UPDATE TABLE_NAME
SET
  TABLE_NAME.EMBEDDING_COLUMN_NAME = (
    SELECT embeddings.values
    FROM SAFE.ML.PREDICT(
      MODEL MODEL_NAME,
      (SELECT TABLE_NAME.DATA_COLUMN_NAME AS content)
    ) @{remote_udf_max_rows_per_rpc=MAX_ROWS}
  ),
  TABLE_NAME.EMBEDDING_VERSION_COLUMN = MODEL_VERSION
WHERE FILTER_CONDITION;

替換下列內容:

  • TABLE_NAME:含有文字資料的資料表名稱
  • EMBEDDING_COLUMN_NAME:要新增生成嵌入的資料欄名稱
  • DATA_COLUMN_NAME:含有文字資料的資料欄名稱
  • MODEL_NAME:Agent Platform 嵌入模型的名稱
  • MAX_ROWS:每個 RPC 的資料列數量上限
  • EMBEDDING_VERSION_COLUMN:這個資料欄用於管理嵌入模型版本,該模型用於補充嵌入
  • MODEL_VERSION:文字嵌入模型的版本
  • FILTER_CONDITION:要套用的可分區篩選條件

使用 SAFE.ML.PREDICT 時,失敗的要求會傳回 NULL。您也可以搭配使用 SAFE.ML.PREDICT 和 WHERE embedding_column IS NULL 篩選器,重新執行查詢,而不必為已計算的欄位計算嵌入。

PostgreSQL

UPDATE TABLE_NAME
SET
  EMBEDDING_COLUMN_NAME = spanner.FLOAT32_ARRAY(spanner.ML_PREDICT_ROW(
    'projects/PROJECT/locations/LOCATION/publishers/google/models/$MODEL_NAME',
    JSONB_BUILD_OBJECT('instances', JSONB_BUILD_ARRAY(JSONB_BUILD_OBJECT('content', DATA_COLUMN_NAME)))
  ) /*@ remote_udf_max_rows_per_rpc=MAX_ROWS */ ->'predictions'->0->'embeddings'->'values'),
  EMBEDDING_VERSION_COLUMN = MODEL_VERSION
WHERE FILTER_CONDITION;

替換下列內容:

  • TABLE_NAME:含有文字資料的資料表名稱
  • EMBEDDING_COLUMN_NAME:要新增生成嵌入的資料欄名稱
  • DATA_COLUMN_NAME:含有文字資料的資料欄名稱
  • PROJECT:託管 Agent Platform 端點的專案
  • LOCATION:Agent Platform 端點的位置
  • MODEL_NAME:Agent Platform 嵌入模型的名稱
  • MODEL_VERSION:Agent Platform 嵌入模型的版本
  • MAX_ROWS:每個 RPC 的資料列數量上限
  • EMBEDDING_VERSION_COLUMN:這個資料欄用於管理文字嵌入模型版本,該模型用於回填嵌入
  • FILTER_CONDITION:要套用的可分區篩選條件

products 資料表的補充查詢範例:

GoogleSQL

UPDATE products
SET
  products.desc_embed = (
    SELECT embeddings.values
    FROM SAFE.ML.PREDICT(
      MODEL embedding_model,
      (SELECT products.description AS content)
    ) @{remote_udf_max_rows_per_rpc=200}
  ),
  products.desc_embed_model_version = 3
WHERE products.desc_embed IS NULL;

PostgreSQL

UPDATE products
SET
  desc_embed = spanner.FLOAT32_ARRAY(spanner.ML_PREDICT_ROW(
    'projects/PROJECT/locations/LOCATION/publishers/google/models/$MODEL_NAME',
    JSONB_BUILD_OBJECT('instances', JSONB_BUILD_ARRAY(JSONB_BUILD_OBJECT('content', description)))
  ) /*@ remote_udf_max_rows_per_rpc=200 */ ->'predictions'->0->'embeddings'->'values'),
  desc_embed_model_version = 3
WHERE desc_embed IS NULL;

如要瞭解最佳做法,請參考下列事項:

  • Spanner API 的預設 gRPC 逾時時間為一小時。視要補充的嵌入數量而定,您可能需要增加這個逾時時間,確保 UPDATE 分區 DML 有足夠的時間完成。詳情請參閱「設定自訂逾時和重試」。

效能和其他注意事項

回填嵌入資料時,請考量下列事項,盡可能提高效能。

節點數量

分區 DML 會在不同分區中平行執行指定的 DML 陳述式。如果執行個體含有大量節點,在執行分區 DML 時,您可能會看到配額錯誤。如果 Agent Platform API 要求因 Agent Platform API 配額限制而受到節流,Spanner 會在分區 DML 交易模式下重試這些失敗作業,最多 20 次。如果發現 Agent Platform 的配額錯誤率偏高,請提高 Agent Platform 的配額。使用 GoogleSQL 時,您也可以透過陳述式層級提示 @{pdml_max_parallelism=DESIRED_NUMBER} 調整平行處理。以下範例將平行處理設為「5」:

GoogleSQL

@{pdml_max_parallelism=5} UPDATE products
SET products.desc_embed =(
  SELECT embeddings.values
  FROM SAFE.ML.PREDICT(MODEL embedding_model, (
        SELECT products.value AS CONTENT
        )
  )
      @{remote_udf_max_rows_per_rpc=200}
),
products.desc_embed_model_version = MODEL_VERSION
WHERE products.desc_embed IS NULL;

資料欄中的文字大小

Agent Platform 嵌入模型對每項文字輸入內容的詞元數量設有上限。不同模型版本的權杖限制也不同。每項 Agent Platform 要求可以有多個輸入文字欄位,但單一要求中的權杖數量有上限。如果是 GoogleSQL 資料庫,當您遇到 INVALID_ARGUMENT 錯誤,且訊息顯示「Request is too large」時,請嘗試縮減批次大小,避免發生錯誤。如要這麼做,您可以在註冊模型時設定 default_batch_size,或使用 @{remote_udf_max_outstanding_rpcs} 查詢提示。

傳送至 Agent Platform 的 API 要求數量

您可以使用查詢提示 @{remote_udf_max_outstanding_rpcs},增加或減少從 Spanner 傳送至 Agent Platform 的要求數量。請注意,提高這項限制可能會增加 Spanner 執行個體的 CPU 和記憶體用量。如果是 GoogleSQL 資料庫,使用這項查詢提示會覆寫為模型設定的 default_batch_size。

監控補充進度

您可以使用系統洞察資訊主頁,監控從 Spanner 傳送至 Agent Platform 的要求數量、延遲時間和網路位元組。

後續步驟