このドキュメントでは、SQL と Vertex AI テキスト エンベディング モデルを使用して、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 データベースの Vertex AI モデル エンドポイントに、テキスト エンベディング モデルを登録します。
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
: Vertex AI テキスト エンベディング モデルの名前PROJECT
: Vertex AI エンドポイントをホストするプロジェクトLOCATION
: Vertex AI エンドポイントのロケーション
PostgreSQL
PostgreSQL 言語では、モデルを登録する必要はありません。エンドポイント名を spanner.ML_PREDICT_ROW
関数呼び出しに直接渡します。
ベスト プラクティスとして、以下を検討してください。
- 割り当ての分離を維持するには、本番環境エンドポイントとは異なるプロジェクトのエンドポイントを使用して、エンベディングを生成してバックフィルします。本番環境トラフィックを処理するよう、本番環境エンドポイントを予約します。
- モデルのエンドポイントが
default_batch_size
の値をサポートしていることを確認します。default_batch_size
は、クエリヒント@{remote_udf_max_rows_per_rpc=NEW_NUMBER}
でオーバーライドできます。各リージョンのdefault_batch_size
の上限については、テキスト スニペットのテキスト エンベディングを取得するをご覧ください。 @latest
ではなく、モデルの特定のバージョン(@003
など)を使用してエンドポイントを定義します。これは、同じテキストに対して生成されたエンベディング ベクトルが、使用するモデルのバージョンによって異なる可能性があるためです。そのため、同じデータセットで異なるバージョンのモデルを使用してエンベディングを生成することは避けてください。また、モデル定義ステートメントでモデルのバージョンを更新しても、このモデルですでに生成されているエンベディングは更新されません。エンベディングのモデルのバージョンを管理する方法の一つとして、モデルのバージョンを格納する列をテーブルに追加する方法もあります。- カスタム チューニングされたテキスト エンベディング モデルは、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
: Vertex AI テキスト エンベディング モデルの名前
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
: Vertex AI エンドポイントをホストするプロジェクトLOCATION
: Vertex AI エンドポイントのロケーションMODEL_NAME
: Vertex AI テキスト エンベディング モデルの名前
エンベディング格納のための列を追加するようソーステーブルを更新する
次に、ソーステーブルのスキーマを更新して、生成されたエンベディングを保存するデータ型 ARRAY<FLOAT32>
の列を追加します。
GoogleSQL
ALTER TABLE TABLE_NAME
ADD COLUMN EMBEDDING_COLUMN_NAME ARRAY<FLOAT32>;
次のように置き換えます。
TABLE_NAME
: ソーステーブルの名前EMBEDDING_COLUMN_NAME
: 生成されたエンベディングを追加する列の名前
PostgreSQL
ALTER TABLE TABLE_NAME
ADD COLUMN EMBEDDING_COLUMN_NAME real[];
次のように置き換えます。
TABLE_NAME
: ソーステーブルの名前EMBEDDING_COLUMN_NAME
: 生成されたエンベディングを追加する列の名前
たとえば、products
テーブルの例を使用して、次のコマンドを実行します。
GoogleSQL
ALTER TABLE Products
ADD COLUMN desc_embed ARRAY<FLOAT32>;
PostgreSQL
ALTER TABLE Products
ADD COLUMN desc_embed real[];
別の列を追加して、エンベディング モデルのバージョンを管理できます。
GoogleSQL
ALTER TABLE Products
ADD COLUMN desc_embed_model_version INT64;
PostgreSQL
ALTER TABLE Products
ADD COLUMN desc_embed_model_version INT8;
Vertex AI の割り当てを増やす
テキスト エンベディング モデルを使用するリージョンで、Vertex AI API の割り当てを増やす必要が生じる場合があります。引き上げをリクエストするには、Vertex AI の割り当ての増加をご覧ください。
詳細については、Vertex AI の割り当てと上限をご覧ください。
エンベディングをバックフィルする
最後に、パーティション化された 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
: Vertex AI エンベディング モデルの名前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
: Vertex AI エンドポイントをホストするプロジェクトLOCATION
: Vertex AI エンドポイントのロケーションMODEL_NAME
: Vertex AI エンベディング モデルの名前MODEL_VERSION
: Vertex AI エンベディング モデルのバージョン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 タイムアウトは 1 時間です。バックフィルするエンベディングの量によっては、
UPDATE
パーティション化 DML が完了するのに十分な時間を確保できるように、タイムアウトの値を増やす必要があります。詳細については、カスタム タイムアウトと再試行を構成するをご覧ください。
パフォーマンスとその他の考慮事項
エンベディング データをバックフィルする際のパフォーマンスを最適化するには、次の点を考慮してください。
ノード数
パーティション化 DML は、指定された DML ステートメントを異なるパーティションで並列に実行します。ノード数の多いインスタンスでは、パーティション化 DML の実行中に割り当てエラーが発生することがあります。Vertex AI API の割り当て上限により Vertex AI API リクエストがスロットルされている場合、Spanner はこういった失敗をパーティション化 DML トランザクション モードで最大 20 回再試行します。Vertex AI で割り当てエラーの発生率が高い場合は、Vertex AI の割り当てを増やしてください。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;
データ列のテキストのサイズ
Vertex AI のエンベディング モデルには、各テキスト入力のトークンの最大数に上限があります。トークン数の上限はモデルのバージョンによって異なります。各 Vertex AI リクエストには複数の入力テキスト フィールドを含めることができますが、1 つのリクエストに存在するトークンの最大数には上限があります。GoogleSQL データベースで「リクエストが大きすぎます」というメッセージとともに INVALID_ARGUMENT
エラーが発生した場合は、バッチサイズを小さくしてエラーを回避してください。これを行うには、モデルの登録時に default_batch_size
を構成するか、@{remote_udf_max_outstanding_rpcs}
クエリヒントを使用します。
Vertex AI に送信された API リクエストの数
クエリヒント @{remote_udf_max_outstanding_rpcs}
を使用して、Spanner から Vertex AI に送信されるリクエストの数を増減できます。この上限を増やすと、Spanner インスタンスの CPU 使用量とメモリ使用量が増加します。GoogleSQL データベースの場合、このクエリヒントを使用すると、モデルに構成された default_batch_size
がオーバーライドされます。
バックフィルの進行状況をモニタリングする
システム分析情報ダッシュボードを使用して、Spanner から Vertex AI に送信されるリクエスト数、レイテンシ、ネットワーク バイト数をモニタリングできます。
次のステップ
- K 最近傍探索を行って類似ベクトル検索を行う方法を確認する。
- エンベディングに関する集中講座で ML とエンベディングの詳細を確認する。
- Vertex AI テキスト エンベディング モデルの詳細を確認する。