このチュートリアルでは、Spanner と Vertex AI を使用して生成 AI アプリケーションを構築する方法について説明します。
このアプリケーションでは、セマンティック類似度検索を実行して、自然言語クエリに一致する商品を見つけることができます。これは、単語の意味とコンテキストを捉えたテキストの数値表現であるエンベディングを使用することで実現されます。Vertex AI モデルを使用してこれらのエンベディングを生成し、Spanner にエンベディングを保存して検索します。このアプローチは、ユーザーが特定のキーワードではなく自然言語で欲しいものを説明する商品検索などのユースケースで特に役立ちます。
次のトピックでは、以下の方法について説明します。
- Google Cloud プロジェクトを作成する
- Spanner インスタンスを作成する
- データベースを作成する
- エンベディング モデルを作成する
- データを Spanner に読み込む
- データのエンベディングを生成する
- KNN ベクトル類似性検索を実行する
- ベクトル インデックスを使用してベクトル検索をスケーリングする
- リソースをクリーンアップする
Spanner の料金の詳細については、Spanner の料金をご覧ください。
Codelab を試すには、Spanner ベクトル検索を使ってみるをご覧ください。
始める前に
請求先アカウントに接続された Google Cloud プロジェクトを作成する必要があります。
- Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Verify that billing is enabled for your Google Cloud project.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Verify that billing is enabled for your Google Cloud project.
- 通常、Spanner API は自動的に有効になります。それ以外の場合は、手動で有効にします。Spanner API を有効にする
- 通常、Vertex AI API は自動的に有効になります。それ以外の場合は、手動で有効にします。Vertex AI API を有効にする
-
インスタンスとデータベースを作成するために必要な権限を取得するには、プロジェクトに対する Cloud Spanner 管理者 (
roles/spanner.admin
)IAM ロールを付与するよう管理者に依頼してください。 -
Cloud Spanner 管理者ロールが付与されていない場合、Spanner グラフに対してクエリを実行するために必要な権限を取得するには、プロジェクトに対する Cloud Spanner データベース リーダー (
roles/spanner.databaseReader
)IAM ロールを付与するよう管理者に依頼してください。 Google Cloud コンソールで、[Spanner] ページに移動します。
Google Cloud プロジェクトを選択するか、まだ作成していない場合は新しく作成します。
次のいずれかを行います。
- まだ Spanner インスタンスを作成していない場合は、[Spanner へようこそ] ページで [プロビジョニングされたインスタンスを作成] をクリックします。
- Spanner インスタンスを作成している場合は、[インスタンス] ページで [インスタンスを作成] をクリックします。
[エディションを選択] ページで、[Enterprise Plus] または [Enterprise] を選択します。
Spanner ベクトル検索は、Enterprise エディションまたは Enterprise Plus エディションでのみ使用できます。異なるエディションを比較するには、[エディションを比較] をクリックします。詳細については、Spanner エディションの概要をご覧ください。
[続行] をクリックします。
[インスタンス名] にインスタンス名(
test-instance
など)を入力します。[インスタンス ID] で、インスタンス ID をそのままにしておくか、変更します。デフォルトでインスタンス名がインスタンス ID になりますが、変更できます。インスタンス名とインスタンス ID は同じものでも異なるものでもかまいません。
[続行] をクリックします。
[構成を選択] で、次の操作を行います。
- [リージョン] を選択したままにします。
- [構成を選択] でリージョンを選択します。選択したリージョンにインスタンスが保存され、複製されます。
- [続行] をクリックします。
[コンピューティング容量を構成する] で、次の操作を行います。
- [ユニットを選択] で、[処理ユニット(PU)] を選択します。
- [スケーリング モードを選択] で [手動で割り当てる] を選択し、[数量] は 1,000 処理ユニットのままにします。
[作成] をクリックします。 Google Cloud コンソールに、作成したインスタンスの [概要] ページが表示されます。
Google Cloud コンソールで、[Spanner インスタンス] ページに移動します。
作成したインスタンスをクリックします(例:
test-instance
)。[概要] で、インスタンスの名前の下にある [データベースを作成] をクリックします。
[データベース名] にデータベース名を入力します。例:
example-db
[データベース言語の選択] で、Google 標準 SQL を選択します。
PostgreSQL 言語では Spanner ベクトル検索を使用できません。
次のスキーマを [DDL テンプレート] エディタタブにコピーして貼り付けます。スキーマは
Products
テーブルを定義します。CREATE TABLE products ( categoryId INT64 NOT NULL, productId INT64 NOT NULL, productName STRING(MAX) NOT NULL, productDescription STRING(MAX) NOT NULL, productDescriptionEmbedding ARRAY<FLOAT32>, createTime TIMESTAMP NOT NULL OPTIONS ( allow_commit_timestamp = true ), inventoryCount INT64 NOT NULL, priceInCents INT64, ) PRIMARY KEY(categoryId, productId);
[暗号化オプションを表示する] で変更は行わないでください。
[作成] をクリックします。 Google Cloud コンソールに、作成したデータベースの [概要] ページが表示されます。
- データベースの [概要] ページで、[Spanner Studio] をクリックします。
- [Spanner Studio] ページで、[ 新しいタブ] をクリックするか、空のエディタタブを使用します。
次のように入力します。
CREATE MODEL EmbeddingsModel INPUT( content STRING(MAX), ) OUTPUT( embeddings STRUCT<values ARRAY<FLOAT32>>, ) REMOTE OPTIONS ( endpoint = '//aiplatform.googleapis.com/projects/PROJECT_ID/locations/us-central1/publishers/google/models/TEXT_EMBEDDING_MODEL' );
次のように置き換えます。
- PROJECT_ID:Google Cloud プロジェクトで一意の永続的な識別子。
- TEXT_EMBEDDING_MODEL: テキスト エンベディング モデルの名前。Vertex AI テキスト エンベディング モデルの一覧については、サポートされているモデルをご覧ください。
[実行] をクリックしてモデルを作成します。
モデルが正常に追加されると、[エクスプローラ] ペインに表示されます。
Spanner Studio の新しいタブで、次の挿入ステートメントをコピーして貼り付けます。
INSERT INTO products (categoryId, productId, productName, productDescription, createTime, inventoryCount, priceInCents) VALUES (1, 1, "Cymbal Helios Helmet", "Safety meets style with the Cymbal children's bike helmet. Its lightweight design, superior ventilation, and adjustable fit ensure comfort and protection on every ride. Stay bright and keep your child safe under the sun with Cymbal Helios!", PENDING_COMMIT_TIMESTAMP(), 100, 10999), (1, 2, "Cymbal Sprout", "Let their cycling journey begin with the Cymbal Sprout, the ideal balance bike for beginning riders ages 2-4 years. Its lightweight frame, low seat height, and puncture-proof tires promote stability and confidence as little ones learn to balance and steer. Watch them sprout into cycling enthusiasts with Cymbal Sprout!", PENDING_COMMIT_TIMESTAMP(), 10, 13999), (1, 3, "Cymbal Spark Jr.", "Light, vibrant, and ready for adventure, the Spark Jr. is the perfect first bike for young riders (ages 5-8). Its sturdy frame, easy-to-use brakes, and puncture-resistant tires inspire confidence and endless playtime. Let the spark of cycling ignite with Cymbal!", PENDING_COMMIT_TIMESTAMP(), 34, 13900), (1, 4, "Cymbal Summit", "Conquering trails is a breeze with the Summit mountain bike. Its lightweight aluminum frame, responsive suspension, and powerful disc brakes provide exceptional control and comfort for experienced bikers navigating rocky climbs or shredding downhill. Reach new heights with Cymbal Summit!", PENDING_COMMIT_TIMESTAMP(), 0, 79999), (1, 5, "Cymbal Breeze", "Cruise in style and embrace effortless pedaling with the Breeze electric bike. Its whisper-quiet motor and long-lasting battery let you conquer hills and distances with ease. Enjoy scenic rides, commutes, or errands with a boost of confidence from Cymbal Breeze!", PENDING_COMMIT_TIMESTAMP(), 72, 129999), (1, 6, "Cymbal Trailblazer Backpack", "Carry all your essentials in style with the Trailblazer backpack. Its water-resistant material, multiple compartments, and comfortable straps keep your gear organized and accessible, allowing you to focus on the adventure. Blaze new trails with Cymbal Trailblazer!", PENDING_COMMIT_TIMESTAMP(), 24, 7999), (1, 7, "Cymbal Phoenix Lights", "See and be seen with the Phoenix bike lights. Powerful LEDs and multiple light modes ensure superior visibility, enhancing your safety and enjoyment during day or night rides. Light up your journey with Cymbal Phoenix!", PENDING_COMMIT_TIMESTAMP(), 87, 3999), (1, 8, "Cymbal Windstar Pump", "Flat tires are no match for the Windstar pump. Its compact design, lightweight construction, and high-pressure capacity make inflating tires quick and effortless. Get back on the road in no time with Cymbal Windstar!", PENDING_COMMIT_TIMESTAMP(), 36, 24999), (1, 9,"Cymbal Odyssey Multi-Tool","Be prepared for anything with the Odyssey multi-tool. This handy gadget features essential tools like screwdrivers, hex wrenches, and tire levers, keeping you ready for minor repairs and adjustments on the go. Conquer your journey with Cymbal Odyssey!", PENDING_COMMIT_TIMESTAMP(), 52, 999), (1, 10,"Cymbal Nomad Water Bottle","Stay hydrated on every ride with the Nomad water bottle. Its sleek design, BPA-free construction, and secure lock lid make it the perfect companion for staying refreshed and motivated throughout your adventures. Hydrate and explore with Cymbal Nomad!", PENDING_COMMIT_TIMESTAMP(), 42, 1299);
[実行] をクリックしてデータを挿入します。
Spanner Studio の新しいタブで、次の更新ステートメントをコピーして貼り付けます。
UPDATE products p1 SET productDescriptionEmbedding = (SELECT embeddings.values FROM ML.PREDICT(MODEL EmbeddingsModel, (SELECT p1.productDescription as content) ) ) WHERE categoryId=1;
[実行] をクリックして、エンベディングを生成します。
ML.PREDICT
を使用して、指定された検索クエリ(「3 歳の子ども用の自転車を購入したい」)のエンベディングを生成します。- このクエリ エンベディングと商品テーブルの各商品の
productDescriptionEmbedding
の間のCOSINE_DISTANCE
を計算して、Cymbal ストアで類似する結果を見つけます。 - 結果をフィルタして、
inventoryCount
が 0 より大きい商品のみを含めます。 - 計算された距離で結果を並べ替え、最も近い上位 5 つの一致と
productName
、productDescription
、inventoryCount
を返します。 Spanner Studio の新しいタブで、次のクエリをコピーして貼り付けます。
SELECT productName, productDescription, inventoryCount, COSINE_DISTANCE( productDescriptionEmbedding, ( SELECT embeddings.values FROM ML.PREDICT( MODEL EmbeddingsModel, (SELECT "I'd like to buy a starter bike for my 3 year old child" AS content)) )) AS distance FROM products WHERE inventoryCount > 0 ORDER BY distance LIMIT 5;
[実行] をクリックすると、検索テキストに最も一致する商品が返されます。
出力例:
/*-----------------+--------------------+----------------+--------------------* | productName | productDescription | inventoryCount | distance | +------------------+--------------------+----------------+--------------------+ | Cymbal Sprout | Let their cycling | 10 | 0.3094387191860244 | | | journey begin with | | | | | the Cymbal Sprout, | | | | | the ideal balance | | | | | bike for beginning | | | | | riders ages 2-4 | | | | | years... | | | | Cymbal Spark Jr | Light, vibrant, | 34 | 0.3412342902117166 | | | and ready for | | | | | adventure, the | | | | | Spark Jr. is the | | | | | perfect first bike | | | | | for young riders | | | | | (ages 5-8)... | | | | Cymbal Helios | Safety meets style | 100 | 0.4197863319656684 | | Helmet | with the Cymbal | | | | | children's bike | | | | | helmet... | | | | Cymbal Breeze | Cruise in style and| 72 | 0.485231776523978 | | | embrace effortless | | | | | pedaling with the | | | | | Breeze electric | | | | | bike... | | | | Cymbal Phoenix | See and be seen | 87 | 0.525101413779242 | | Lights | with the Phoenix | | | | | bike lights... | | | *------------------+--------------------+----------------+--------------------*/
Spanner Studio の新しいタブで、次の DDL ステートメントをコピーして貼り付け、
productDescriptionEmbedding
列を再作成します。ALTER TABLE products DROP COLUMN productDescriptionEmbedding; ALTER TABLE products ADD COLUMN productDescriptionEmbedding ARRAY<FLOAT32>(vector_length=>VECTOR_LENGTH_VALUE);
VECTOR_LENGTH_VALUE
は、選択したエンベディング モデルの最大出力ディメンションに置き換えます。[実行] をクリックします。
次の挿入ステートメントをコピーして貼り付け、ベクトル エンベディングを再生成します。
UPDATE products p1 SET productDescriptionEmbedding = (SELECT embeddings.values from ML.PREDICT(MODEL EmbeddingsModel, (SELECT p1.productDescription as content))) WHERE categoryId=1;
[実行] をクリックします。
次の DDL ステートメントをコピーして貼り付け、ベクトル インデックスを作成します。
CREATE VECTOR INDEX ProductDescriptionEmbeddingIndex ON products(productDescriptionEmbedding) WHERE productDescriptionEmbedding IS NOT NULL OPTIONS ( distance_type = 'COSINE' );
[実行] をクリックします。
- SQL クエリ内ではなく、プロンプト エンベディングを個別に生成します。
- エンベディングの結果をクエリにコピーします。
FORCE_INDEX
ヒントを使用して、新しいベクトル インデックスを参照します。@{force_index=ProductDescriptionEmbeddingIndex}
COSINE_DISTANCE
ではなく、APPROX_COSINE_DISTANCE
ベクトル距離関数を使用します。JSON '{"num_leaves_to_search": num_leaves}'
オプションは必須です。Spanner Studio の新しいタブで、次のクエリをコピーして貼り付け、プロンプト エンベディングを生成します。
-- Generate the prompt embedding SELECT embeddings.values FROM ML.PREDICT( MODEL EmbeddingsModel, (SELECT "I'd like to buy a starter bike for my 3 year old child" as content) );
[実行] をクリックします。
embeddings.values
の結果をコピーします。次のクエリの
embedding
を、前の手順でコピーしたエンベディング結果に置き換えます。-- Update embedding query using the vector index SELECT productName, productDescription, inventoryCount, (APPROX_COSINE_DISTANCE(productDescriptionEmbedding, array<float32>[embedding], options => JSON '{\"num_leaves_to_search\": 10}')) as distance FROM products @{force_index=ProductDescriptionEmbeddingIndex} WHERE productDescriptionEmbedding IS NOT NULL AND inventoryCount > 0 ORDER BY distance LIMIT 5;
新しい SQL クエリは次のようになります。
SELECT productName, productDescription, count, (APPROX_COSINE_DISTANCE(productDescriptionEmbedding, array<float32>[-0.00457216799,-0.0771846101,-0.0319350846,0.0352052487,-0.0457422845,0.0183265656...], options => JSON '{\"num_leaves_to_search\": 10}')) as distance FROM products @{force_index=ProductDescriptionEmbeddingIndex} WHERE productDescriptionEmbedding IS NOT NULL AND inventoryCount > 0 ORDER BY distance LIMIT 5;
出力例:
/*-----------------+--------------------+----------------+--------------------* | productName | productDescription | inventoryCount | distance | +------------------+--------------------+----------------+--------------------+ | Cymbal Sprout | Let their cycling | 10 | 0.30935457151661594| | | journey begin with | | | | | the Cymbal Sprout, | | | | | the ideal balance | | | | | bike for beginning | | | | | riders ages 2-4 | | | | | years... | | | | Cymbal Spark Jr | Light, vibrant, | 34 | 0.34116496551593656| | | and ready for | | | | | adventure, the | | | | | Spark Jr. is the | | | | | perfect first bike | | | | | for young riders | | | | | (ages 5-8)... | | | | Cymbal Helios | Safety meets style | 100 | 0.4198014303921187 | | Helmet | with the Cymbal | | | | | children's bike | | | | | helmet... | | | | Cymbal Breeze | Cruise in style and| 72 | 0.4850674854267337 | | | embrace effortless | | | | | pedaling with the | | | | | Breeze electric | | | | | bike... | | | | Cymbal Phoenix | See and be seen | 87 | 0.525101413779242 | | Lights | with the Phoenix | | | | | bike lights... | | | *------------------+--------------------+----------------+--------------------*/
Cymbal Sprout の
APPROX_COSINE_DISTANCE
は 0.30935457151661594 で、元のクエリとの類似度が最も高くなっています。ベクトル関数と類似性の関係の解釈の詳細については、ベクトル距離関数から選択してベクトル エンベディングの類似性を測定するをご覧ください。
Google Cloud コンソールで、[Spanner インスタンス] ページに移動します。
「test-instance」など、削除するデータベースがあるインスタンスの名前をクリックします。
example-db など、削除するデータベースの名前をクリックします。
[データベースの概要] ページで、[データベースを削除] をクリックします。
データベース名を入力して [削除] をクリックし、データベースの削除を確定します。
Google Cloud コンソールで、[Spanner インスタンス] ページに移動します。
「test-instance」など、削除するインスタンスの名前をクリックします。
[インスタンスの削除] をクリックします。
インスタンス名を入力し [削除] をクリックして、インスタンスの削除を確定します。
- Spanner の k 最近傍(KNN)機能の詳細を確認する。
- Spanner の近似最近傍(ANN)機能の詳細を確認する。
- Vertex AI を使用して SQL でオンライン予測を実行する方法について学習する。
インスタンスの作成
Spanner を初めて使用する際は、インスタンスを作成する必要があります。インスタンスとは、Spanner データベースによって使用されるリソースの割り当てのことです。このセクションでは、 Google Cloud コンソールを使用してインスタンスを作成する方法について説明します。
データベースの作成
インスタンスの実行が開始されたら、データベースを作成できます。スキーマはデータベースで定義します。
エンベディング モデルを作成する
Spanner で CREATE MODEL
DDL ステートメントを使用すると、データベースから Vertex AI モデルのエンドポイントへの参照が登録されます。モデルを登録したら、ML.PREDICT
関数を使用して、クエリでモデルにアクセスできます。
次の例では、Vertex AI のテキスト エンベディング モデルを登録する方法を示します。このモデルは、類似性検索を実行して、データベース内の類似商品を検索するために使用されます。
データの読み込み
Cymbal サンプルデータを products
テーブルに読み込むには、次の操作を行います。
ベクトル エンベディングを生成する
モデルを登録して Spanner にデータを読み込んだら、データの商品説明を使用してベクトル エンベディングを生成できます。ベクトル エンベディングは、単語の意味とコンテキストを捉える数値にテキストデータを変換します。この変換は、セマンティック検索を実行するうえで不可欠です。
このステップでは、ML.PREDICT
を使用して productDescription
列からエンベディングを生成し、productDescriptionEmbedding
列にデータを入力します。これにより、次のステップでベクトル類似性検索を実行できます。
ベクトル類似検索を行う
次の例では、SQL クエリを使用して自然言語検索リクエストを指定します。SQL クエリは、以前に生成したベクトル エンベディングを使用してベクトル類似度検索を実行します。クエリは、次の処理を行って検索を実行します。
近似最近傍を使用するようにベクトル検索をスケーリングする
前のベクトル検索の例では、正確な k 近傍法(KNN)ベクトル検索を使用しています。KNN ベクトル距離関数(コサイン距離、ユークリッド距離、ドット積)は、Spanner データの特定のサブセットをクエリできる場合に役立ちます。KNN 検索では、クエリベクトルとデータベース内のすべてのベクトルの間の正確な距離が計算されるため、データをパーティショニングできる場合に効率的です。クエリで特定のフィルタなしでクエリベクトルとデータベース内のすべてのベクトルを比較する必要があり、クエリを独立したサブクエリに分割できない場合は、KNN を使用するとパフォーマンスのボトルネックが発生する可能性があります。このような状況では、近似最近傍(ANN)ベクトル検索が役立ちます。詳細については、近似最近傍を検索するをご覧ください。
ワークロードをパーティショニングできず、大量のデータがある場合は、ANN ベクトル検索を使用して、大規模なデータセットのクエリ パフォーマンスを向上させることができます。
Spanner で ANN ベクトル検索をスケーリングして使用する手順は次のとおりです。
ベクトル インデックスを作成する
Spanner は、Google Research の Scalable Nearest Neighbor(ScaNN)を活用する専用のベクトル インデックスを使用して、ANN ベクトル検索を高速化します。
データセットにベクトル インデックスを作成するには、productDescriptionEmbeddings
列を変更して vector_length
アノテーションを定義する必要があります。vector_length
アノテーションは、各ベクトルのディメンションを示します。次の DDL ステートメントは、productDescriptionEmbedding
列を削除し、vector_length
を使用して再作成します。ベクトルの最大長(ディメンション)は、選択したエンベディング モデルによって異なります。
ANN ベクトル距離関数を使用する
Spanner で ANN ベクトル検索を使用するには、SQL クエリで次の点を変更します。
クリーンアップ
このセクションでは、 Google Cloud コンソールを使用してリソースをクリーンアップする方法について説明します。Cloud 請求先アカウントに追加料金が課されないように、設定時に作成したデータベースとインスタンスを削除します。インスタンスを削除すると、そのインスタンス内に作成されたすべてのデータベースが削除されます。