100 万個のベクトル、ループなし: AlloyDB を使用してエンベディングを大規模に生成する

1. 概要

この Codelab では、スケーラブルなナレッジベース検索アプリケーションを構築します。Python スクリプトとループを使用してベクトル エンベディングを生成する複雑な ETL パイプラインを管理する代わりに、AlloyDB AI を使用して、単一の SQL コマンドでデータベース内でエンベディングの生成をネイティブに処理します。

d4324260c68d4a70.png

作成するアプリの概要

高パフォーマンスの「検索可能な」ナレッジベース データベース アプリケーション。

学習内容

ここでは以下について学びます。

  • AlloyDB クラスタをプロビジョニングし、AI 拡張機能を有効にする。
  • SQL を使用して合成データ(50,000 行以上)を生成する。
  • バッチ処理を使用して、データセット全体のベクトル エンベディングをバックフィルする。
  • リアルタイム増分トリガーを設定して、新しいデータを自動的に埋め込みます。
  • 「Flexing Context」のハイブリッド検索(ベクトル + SQL フィルタ)を実行します。

要件

  • ブラウザ(Chrome、Firefox など)
  • 課金を有効にした Google Cloud プロジェクト
  • SQL に関する基本的な知識。

2. 始める前に

プロジェクトを作成する

  1. Google Cloud コンソールのプロジェクト選択ページで、Google Cloud プロジェクトを選択または作成します。
  2. Cloud プロジェクトに対して課金が有効になっていることを確認します。詳しくは、プロジェクトで課金が有効になっているかどうかを確認する方法をご覧ください。
  3. Google Cloud 上で動作するコマンドライン環境の Cloud Shell を使用します。Google Cloud コンソールの上部にある「Cloud Shell をアクティブにする」アイコンをクリックします。

[Cloud Shell をアクティブにする] ボタンの画像

  1. Cloud Shell に接続したら、次のコマンドを使用して、すでに認証済みであることと、プロジェクトがプロジェクト ID に設定されていることを確認します。
gcloud auth list
  1. Cloud Shell で次のコマンドを実行して、gcloud コマンドがプロジェクトを認識していることを確認します。
gcloud config list project
  1. プロジェクトが設定されていない場合は、次のコマンドを使用して設定します。
gcloud config set project <YOUR_PROJECT_ID>
  1. 必要な API を有効にする: リンクにアクセスして API を有効にします。

または、gcloud コマンドを使用することもできます。gcloud コマンドとその使用方法については、ドキュメントをご覧ください。

gcloud services enable \
  alloydb.googleapis.com \
  compute.googleapis.com \
  cloudresourcemanager.googleapis.com \
  servicenetworking.googleapis.com \
  aiplatform.googleapis.com

注意点とトラブルシューティング

「ゴースト プロジェクト」症候群

gcloud config set project を実行したが、実際にはコンソール UI で別のプロジェクトを表示している。左上のプルダウンでプロジェクト ID を確認してください。

お支払いバリケード

プロジェクトを有効にしたが、請求先アカウントを忘れた。AlloyDB は高性能エンジンです。「ガソリン タンク」(課金)が空の状態では始動しません。

API 伝播ラグ

[API を有効にする] をクリックしたのに、コマンドラインに Service Not Enabled と表示される。60 秒ほど待ちます。クラウドがニューロンを起動するまで、しばらくお待ちください。

割り当ての沼

新しいトライアル アカウントを使用している場合、AlloyDB インスタンスのリージョン割り当てに達する可能性があります。us-central1 が失敗した場合は、us-east1 を試してください。

「非表示」のサービス エージェント

AlloyDB サービス エージェントに aiplatform.user ロールが自動的に付与されない場合があります。SQL クエリが Gemini と通信できない場合は、通常、これが原因です。

3. データベースの設定

このラボでは、テストデータのデータベースとして AlloyDB を使用します。クラスタを使用して、データベースやログなどのすべてのリソースを保持します。各クラスタには、データへのアクセス ポイントを提供するプライマリ インスタンスがあります。テーブルには実際のデータが格納されます。

テスト データセットを読み込む AlloyDB クラスタ、インスタンス、テーブルを作成しましょう。

  1. ボタンをクリックするか、Google Cloud コンソール ユーザーがログインしているブラウザに以下のリンクをコピーします。

  1. このステップが完了すると、リポジトリがローカルの Cloud Shell エディタにクローンされ、プロジェクト フォルダから以下のコマンドを実行できるようになります(プロジェクト ディレクトリにいることを確認することが重要です)。
sh run.sh
  1. 次に、UI を使用します(ターミナルのリンクをクリックするか、ターミナルの [ウェブでプレビュー] リンクをクリックします)。
  2. プロジェクト ID、クラスタ名、インスタンス名の詳細を入力して開始します。
  3. ログがスクロールしている間にコーヒーを飲みながら、バックグラウンドでどのように処理が行われているかについて、こちらで確認できます。10 ~ 15 分ほどかかることがあります。

注意点とトラブルシューティング

「忍耐」の問題

データベース クラスタは重いインフラストラクチャです。「停止しているように見える」ためにページを更新したり、Cloud Shell セッションを強制終了したりすると、部分的にプロビジョニングされた「ゴースト」インスタンスが作成され、手動で介入しないと削除できなくなる可能性があります。

リージョンの不一致

us-central1 で API を有効にしたが、asia-south1 でクラスタをプロビジョニングしようとすると、割り当ての問題やサービス アカウントの権限の遅延が発生する可能性があります。ラボ全体で 1 つのリージョンを使用してください。

ゾンビ クラスタ

以前に同じ名前のクラスタを使用し、削除していない場合、スクリプトはクラスタ名がすでに存在することを示すことがあります。クラスタ名はプロジェクト内で一意にする必要があります。

Cloud Shell のタイムアウト

コーヒー ブレイクに 30 分かかると、Cloud Shell がスリープ状態になり、sh run.sh プロセスが切断される可能性があります。タブをアクティブな状態に保ってください。

4. スキーマのプロビジョニング

このステップでは、次の内容について説明します。

879263c907f3cac6.png

AlloyDB クラスタとインスタンスが実行されたら、AlloyDB Studio SQL エディタに移動して AI 拡張機能を有効にし、スキーマをプロビジョニングします。

1e3ac974b18a8113.png

インスタンスの作成が完了するまで待つ必要がある場合があります。完了したら、クラスタの作成時に作成した認証情報を使用して AlloyDB にログインします。PostgreSQL への認証には、次のデータを使用します。

  • ユーザー名: 「postgres」
  • データベース: 「postgres」
  • パスワード: 「alloydb」(または作成時に設定したパスワード)

AlloyDB Studio への認証が成功すると、エディタに SQL コマンドを入力できるようになります。最後のウィンドウの右側にあるプラス記号を使用して、複数のエディタ ウィンドウを追加できます。

28cb9a8b6aa0789f.png

エディタ ウィンドウで AlloyDB のコマンドを入力し、必要に応じて [実行]、[フォーマット]、[クリア] のオプションを使用します。

拡張機能を有効にする

このアプリを構築するには、拡張機能 pgvector と google_ml_integration を使用します。pgvector 拡張機能を使用すると、ベクトル エンベディングを保存して検索できます。google_ml_integration 拡張機能は、Vertex AI 予測エンドポイントにアクセスして SQL で予測を取得するために使用する関数を提供します。次の DDL を実行して、これらの拡張機能を有効にします。

CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE;
CREATE EXTENSION IF NOT EXISTS vector;

テーブルを作成する

スケールを実証するにはデータセットが必要です。CSV をインポートする代わりに、SQL を使用して 50,000 行の合成「ヘルプ記事」を即座に生成します。

AlloyDB Studio で次の DDL ステートメントを使用してテーブルを作成できます。

-- 1. Create the table
CREATE TABLE help_articles (
    id SERIAL PRIMARY KEY,
    title TEXT,
    category TEXT,
    product_version TEXT,
    content_body TEXT,
    embedding vector(768) -- Dimension for text-embedding-005
);

-- 2. Generate 50,000 rows of synthetic data
INSERT INTO help_articles (title, category, product_version, content_body)
SELECT
    'Help Article ' || i,
    CASE 
        WHEN i % 3 = 0 THEN 'Billing' 
        WHEN i % 3 = 1 THEN 'Technical' 
        ELSE 'General' 
    END,
    CASE 
        WHEN i % 2 = 0 THEN '2.0' 
        ELSE '1.0' 
    END,
    'This article covers common issues regarding ' || 
    CASE 
        WHEN i % 3 = 0 THEN 'payment failures, invoice disputes, and credit card updates.'
        WHEN i % 3 = 1 THEN 'connection timeouts, latency issues, and API errors.'
        ELSE 'account profile settings, password resets, and user roles.' 
    END
FROM generate_series(1, 50000) AS i;

item_vector 列には、テキストのベクトル値を格納できます。

データを確認します。

SELECT count(*) FROM help_articles;
-- Output: 50000

データベース フラグを有効にする

インスタンス構成コンソールに移動し、[Edit Primary] をクリックして、[Advanced Configuration] に移動し、[Add Database Flags] をクリックします。

  1. google_ml_integration.enable_model_support フラグが on に設定されていることを確認します:

設定されていない場合は、フラグのプルダウンに入力して [ON] に設定し、インスタンスを更新します。

  1. google_ml_integration.enable_faster_embedding_generation フラグがオンに設定されていることを確認します。

設定されていない場合は、フラグのプルダウンで入力して [ON] に設定し、インスタンスを更新します。

データベース フラグを構成する手順は次のとおりです。

  1. Google Cloud コンソールで [クラスタ] ページに移動します。

[クラスタ] に移動

  1. [リソース名] 列でクラスタをクリックします。
  2. [概要] ページで、クラスタ内の [インスタンス] に移動し、インスタンスを選択して [編集] をクリックします。
  3. インスタンスに対してデータベース フラグの追加、変更、または削除を行います。

フラグを追加する

  1. インスタンスにデータベース フラグを追加するには、[フラグを追加] をクリックします。
  2. [新しいデータベース フラグ] リストからフラグを選択します。
  3. フラグの値を指定します。
  4. [完了] をクリックします。
  5. [インスタンスを更新] をクリックします。
  6. google_ml_integration 拡張機能のバージョンが 1.5.2 以降であることを確認します。

拡張機能のバージョンを確認するには、次のコマンドを使用します。

SELECT extversion FROM pg_extension WHERE extname = 'google_ml_integration';

拡張機能をより新しいバージョンに更新する必要がある場合は、次のコマンドを使用します。

ALTER EXTENSION google_ml_integration UPDATE;

権限を付与

  1. ユーザーが自動エンベディング生成を管理できるようにするには、google_ml.embed_gen_progress テーブルと google_ml.embed_gen_settings テーブルに対する INSERT、UPDATE、DELETE の各権限を付与します。
GRANT INSERT, UPDATE, DELETE ON google_ml.embed_gen_progress TO postgres;

「postgres」は、権限が付与される USER_NAME です。

  1. 次のステートメントを実行して、「embedding」関数の実行権限を付与します。
GRANT EXECUTE ON FUNCTION embedding TO postgres;

AlloyDB サービス アカウントに Vertex AI ユーザーロールを付与する

Google Cloud IAM コンソールから、AlloyDB サービス アカウント(service-<<PROJECT_NUMBER>>@gcp-sa-alloydb.iam.gserviceaccount.com のようなアカウント)に「Vertex AI ユーザー」ロールへのアクセス権を付与します。PROJECT_NUMBER にはプロジェクト番号が入ります。

または、Cloud Shell ターミナルから次のコマンドを実行します。

PROJECT_ID=$(gcloud config get-value project)


gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:service-$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")@gcp-sa-alloydb.iam.gserviceaccount.com" \
--role="roles/aiplatform.user"

注意点とトラブルシューティング

「パスワードを忘れる」ループ

「ワンクリック」設定を使用し、パスワードを忘れた場合は、コンソールのインスタンスの基本情報ページに移動し、[編集] をクリックして postgres パスワードをリセットします。

「拡張機能が見つかりません」というエラー

CREATE EXTENSION が失敗した場合、多くは、インスタンスが最初のプロビジョニングから「メンテナンス」または「更新中」の状態のままになっていることが原因です。インスタンスの作成ステップが完了しているかどうかを確認し、必要に応じて数秒待ちます。

5. 「ワンショット」ベクトル生成

これがこのラボの中核です。この 50,000 行を処理する Python ループを記述する代わりに、ai.initialize_embeddings 関数を使用します。

この 1 つのコマンドで次の 2 つの処理が行われます。

  1. 既存のすべての行をバックフィルします。
  2. トリガーを作成して、将来の行を自動的に埋め込みます。

AlloyDB クエリエディタから次の SQL ステートメントを実行します。

CALL ai.initialize_embeddings(
  model_id => 'text-embedding-005',
  table_name => 'help_articles',
  content_column => 'content_body',
  embedding_column => 'embedding',
  incremental_refresh_mode => 'transactional'
);

エンベディングを確認する

embedding 列にデータが入力されていることを確認します。

SELECT id, left(content_body, 30), substring(embedding::text, 1, 30) as vector_partial 
FROM help_articles;

次のような結果が表示されます。

a872b8926a164275.png

何が起きたのでしょうか?

  1. 大規模なバックフィル: 既存の 50,000 行を自動的にスキャンし、Vertex AI を介してエンベディングを生成します。
  2. 自動化: incremental_refresh_mode => 'transactional' を設定すると、AlloyDB は内部トリガーを自動的に設定します。help_articles に挿入された新しい行には、エンベディングが即座に生成されます。
  3. 必要に応じて、incremental_refresh_mode => ‘None' を設定して、一括更新を行うステートメントのみを取得し、ai.refresh_embeddings() を手動で呼び出してすべての行のエンベディングを更新できます。

Kafka キュー、Python ワーカー、移行スクリプトを 6 行の SQL に置き換えました。すべての属性の詳細については、公式ドキュメントをご覧ください。

リアルタイム トリガーのテスト

「Zero Loop」自動化が新しいデータに対して機能することを確認しましょう。

  1. 新しい行を挿入する:
INSERT INTO help_articles (title, category, product_version, content_body)
VALUES ('New Scaling Guide', 'Technical', '2.0', 'How to scale AlloyDB to millions of transactions.');
  1. すぐに確認する:
SELECT embedding FROM help_articles WHERE title = 'New Scaling Guide';

結果:

外部スクリプトを実行しなくても、ベクトルが即座に生成されることがわかります。

チューニング バッチサイズ

現在、AlloyDB のデフォルトのバッチサイズは 50 です。デフォルト設定でも十分に機能しますが、AlloyDB では、独自のモデルやデータセットに合わせて最適な構成を調整することもできます。

CALL ai.initialize_embeddings(
  model_id => 'text-embedding-005',
  table_name => 'help_articles',
  content_column => 'content_body',
  embedding_column => 'embedding',
  incremental_refresh_mode => 'transactional',
  batch_size => 20
);

ただし、ユーザーはパフォーマンスを制限する可能性がある割り当て上限に注意する必要があります。推奨される AlloyDB の割り当てを確認するには、ドキュメントの「始める前に」セクションをご覧ください。

注意点とトラブルシューティング

IAM の伝播ギャップ

gcloud IAM コマンドを実行しましたが、SQL CALL が権限エラーで失敗します。IAM の変更が Google バックボーンに反映されるまでに少し時間がかかることがあります。一息つきましょう。

ベクトル ディメンションの不一致

help_articles テーブルは、content_body 列で VECTOR(768) に設定されています。後で別のモデル(1536 次元のモデルなど)を使用しようとすると、挿入が急増します。text-embedding-005 を使用する。

6. Flexing Context Search

次に、ハイブリッド検索を実行します。セマンティックな理解(ベクトル)とビジネス ロジック(SQL フィルタ)を組み合わせます。

次のクエリを実行して、プロダクト バージョン 2.0 に固有の請求に関する問題を見つけます。

SELECT
  title,
  left(content_body, 100) as content_snippet,
  1 - (embedding <=> embedding('text-embedding-005', 'Invoice did not go through')::vector) as relevance
FROM help_articles
WHERE category = 'Billing'  -- Hard SQL Filter
  AND product_version = '2.0' -- Hard SQL Filter
ORDER BY relevance DESC
LIMIT 5;

これがコンテキストの調整です。検索は、厳格なビジネス制約(バージョン 2.0)を尊重しながら、ユーザーの意図(「請求に関する問題」)を理解するために「柔軟に」対応します。

f0fdb50d6195c462.png

スタートアップと移行に最適な理由

  1. インフラストラクチャの負債がゼロ: 個別のベクトル DB(Pinecone / Milvus)をスピンアップしていません。別の ETL ジョブを作成していません。すべて Postgres にあります。
  2. リアルタイム更新: 「トランザクション」モードを使用すると、検索インデックスが古くなることはありません。データが commit された時点で、ベクトル対応になります。
  3. スケール: AlloyDB は Google のインフラストラクチャ上に構築されています。Python スクリプトよりも高速に、数百万のベクトルを一括生成できます。

注意点とトラブルシューティング

本番環境のパフォーマンスの問題

問題: 50,000 行の場合は高速。カテゴリ フィルタの選択性が不十分な場合、100 万行に対して非常に遅くなります。解決策: ベクトル インデックスを追加します。本番環境のスケールでは、インデックスを作成する必要があります。CREATE INDEX ON help_articles USING hnsw (embedding vector_cosine_ops);インデックスの使用状況を確認する: EXPLAIN ANALYZE SELECT ... を実行して、データベースがインデックスを使用しており、シーケンシャル スキャンを実行していないことを確認します。

「モデルの不一致」という大惨事

問題: CALL プロシージャで text-embedding-005 を使用して列を初期化しました。SELECT クエリ関数 embedding('model-name', ...) で誤って別のモデル(text-embedding-004 や OSS モデルなど)を使用すると、ディメンションは一致する(768)可能性がありますが、ベクトル空間はまったく異なります。クエリはエラーなしで実行されますが、結果はまったく無関係です(関連性スコアがゴミになります)。トラブルシューティング:ai.initialize_embeddings の model_id が SELECT クエリの model_id と完全に一致していることを確認します。

「サイレント エンプティ」の結果(過剰なフィルタリング)

問題: ハイブリッド検索は「AND」演算です。セマンティック一致と SQL 一致が必要です。ユーザーが「請求に関するヘルプ」を検索しても、product_version 列に ‘2.0' ではなく ‘2.0.1' が含まれている場合、ベクトル一致が 99% であっても、結果は 0 行になります。トラブルシューティング:

  • まず、ベクトル並べ替えなしでクエリを実行して、SQL フィルタ(WHERE category...)が実際にデータを返しているかどうかを確認します。
  • 大文字と小文字が区別されているかどうかを確認します(Billing と billing)。

4. 権限 / 割り当てエラー(500 エラー)

問題: SELECT 句の embedding() 関数は、Vertex AI に対してリアルタイムのネットワーク呼び出しを行います。データベース サービス アカウントが Vertex AI ユーザーロールを失った場合、または Vertex AI API の割り当て(QPM)に達した場合、SQL クエリ全体が失敗します。トラブルシューティング:

  • AlloyDB の Cloud Logging を確認します。
  • IAM ロールがまだ有効であることを確認します。
  • 高い復元力が必要な場合は、ストアド プロシージャの TRY/CATCH ブロックに関数をラップします。

5. Null エンベディング

問題:モデルが完全に初期化される前にデータを挿入した場合、またはバックグラウンド ワーカーが失敗した場合、一部の行の embedding 列に NULL が含まれることがあります。NULL <=> Vector は NULL を返します。これらの行は並べ替え順から除外されます。トラブルシューティング:

  • SELECT count(*) FROM help_articles WHERE embedding IS NULL; を実行して、100% のカバレッジを確認します。

7. クリーンアップ

このラボが完了したら、AlloyDB クラスタとインスタンスを忘れずに削除してください。

クラスタとそのインスタンスをクリーンアップする必要があります。

8. 完了

スケーラブルなナレッジベース検索アプリケーションを構築できました。Python スクリプトとループを使用してベクトル エンベディングを生成する複雑な ETL パイプラインを管理する代わりに、AlloyDB AI を使用して、単一の SQL コマンドでデータベース内でエンベディングの生成をネイティブに処理しました。

学習した内容

  • データ処理用の「Python For-Loop」を廃止しました。
  • 1 つの SQL コマンドで 50,000 個のベクトルを生成しました。
  • トリガーを使用して、将来のベクトル生成を自動化しました。
  • ハイブリッド検索を実行しました。

次のステップ