AlloyDB AI でベクトル エンベディングを使ってみる

1. はじめに

この Codelab では、ベクトル検索と Vertex AI エンベディングを組み合わせて AlloyDB AI を使用する方法について学習します。

17e86406ab251142.png

前提条件

  • Google Cloud コンソールの基本的な知識
  • コマンドライン インターフェースと Google Shell の基本的なスキル

学習内容

  • AlloyDB クラスタとプライマリ インスタンスをデプロイする方法
  • Google Compute Engine VM から AlloyDB に接続する方法
  • データベースを作成し、AlloyDB AI を有効にする方法
  • データベースにデータを読み込む方法
  • AlloyDB で Vertex AI エンベディング モデルを使用する方法
  • Vertex AI 生成モデルを使用して結果を拡充する方法
  • ベクトル インデックスを使用してパフォーマンスを改善する方法

必要なもの

  • Google Cloud アカウントと Google Cloud プロジェクト
  • ウェブブラウザ(Chrome など)

2. 設定と要件

セルフペース型の環境設定

  1. Google Cloud Console にログインして、プロジェクトを新規作成するか、既存のプロジェクトを再利用します。Gmail アカウントも Google Workspace アカウントもまだお持ちでない場合は、アカウントを作成してください。

fbef9caa1602edd0.png

a99b7ace416376c4.png

5e3ff691252acf41.png

  • プロジェクト名は、このプロジェクトの参加者に表示される名称です。Google API では使用されない文字列です。いつでも更新できます。
  • プロジェクト ID は、すべての Google Cloud プロジェクトにおいて一意でなければならず、不変です(設定後は変更できません)。Cloud コンソールでは一意の文字列が自動生成されます。通常は、この内容を意識する必要はありません。ほとんどの Codelab では、プロジェクト ID(通常は PROJECT_ID と識別されます)を参照する必要があります。生成された ID が好みではない場合は、ランダムに別の ID を生成できます。または、ご自身で試して、利用可能かどうかを確認することもできます。このステップ以降は変更できず、プロジェクトを通して同じ ID になります。
  • なお、3 つ目の値として、一部の API が使用するプロジェクト番号があります。これら 3 つの値について詳しくは、こちらのドキュメントをご覧ください。
  1. 次に、Cloud のリソースや API を使用するために、Cloud コンソールで課金を有効にする必要があります。この Codelab の操作をすべて行って、費用が生じたとしても、少額です。このチュートリアルの終了後に請求が発生しないようにリソースをシャットダウンするには、作成したリソースを削除するか、プロジェクトを削除します。Google Cloud の新規ユーザーは、300 米ドル分の無料トライアル プログラムをご利用いただけます。

Cloud Shell を起動する

Google Cloud はノートパソコンからリモートで操作できますが、この Codelab では、Google Cloud Shell(Cloud 上で動作するコマンドライン環境)を使用します。

Google Cloud Console で、右上のツールバーにある Cloud Shell アイコンをクリックします。

55efc1aaa7a4d3ad.png

プロビジョニングと環境への接続にはそれほど時間はかかりません。完了すると、次のように表示されます。

7ffe5cbb04455448.png

この仮想マシンには、必要な開発ツールがすべて用意されています。永続的なホーム ディレクトリが 5 GB 用意されており、Google Cloud で稼働します。そのため、ネットワークのパフォーマンスと認証機能が大幅に向上しています。この Codelab での作業はすべて、ブラウザ内から実行できます。インストールは不要です。

3. はじめに

API を有効にする

出力:

Cloud Shell で、プロジェクト ID が設定されていることを確認します。

gcloud config set project [YOUR-PROJECT-ID]

環境変数 PROJECT_ID を設定します。

PROJECT_ID=$(gcloud config get-value project)

必要なサービスをすべて有効にします。

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

想定される出力

student@cloudshell:~ (test-project-001-402417)$ gcloud config set project test-project-001-402417
Updated property [core/project].
student@cloudshell:~ (test-project-001-402417)$ PROJECT_ID=$(gcloud config get-value project)
Your active configuration is: [cloudshell-14650]
student@cloudshell:~ (test-project-001-402417)$ 
student@cloudshell:~ (test-project-001-402417)$ gcloud services enable alloydb.googleapis.com \
                       compute.googleapis.com \
                       cloudresourcemanager.googleapis.com \
                       servicenetworking.googleapis.com \
                       aiplatform.googleapis.com
Operation "operations/acat.p2-4470404856-1f44ebd8-894e-4356-bea7-b84165a57442" finished successfully.

Vertex AI エンベディング モデルを使用するようにデフォルトのリージョンを構成します。Vertex AI で利用可能なロケーションの詳細を確認する。この例では、us-central1 リージョンを使用しています。

gcloud config set compute/region us-central1

4. AlloyDB をデプロイする

AlloyDB クラスタを作成する前に、VPC で使用可能なプライベート IP 範囲を割り振り、将来の AlloyDB インスタンスで使用できるようにする必要があります。ない場合は、作成して Google 内部サービスで使用するように割り当てる必要があります。その後、クラスタとインスタンスを作成できます。

プライベート IP 範囲を作成する

AlloyDB の VPC でプライベート サービス アクセスを構成する必要があります。ここでは、プロジェクトに「デフォルト」の VPC ネットワークがあり、すべてのアクションで使用されることを前提としています。

プライベート IP 範囲を作成します。

gcloud compute addresses create psa-range \
    --global \
    --purpose=VPC_PEERING \
    --prefix-length=24 \
    --description="VPC private service access" \
    --network=default

割り振られた IP 範囲を使用してプライベート接続を作成します。

gcloud services vpc-peerings connect \
    --service=servicenetworking.googleapis.com \
    --ranges=psa-range \
    --network=default

想定されるコンソール出力:

student@cloudshell:~ (test-project-402417)$ gcloud compute addresses create psa-range \
    --global \
    --purpose=VPC_PEERING \
    --prefix-length=24 \
    --description="VPC private service access" \
    --network=default
Created [https://www.googleapis.com/compute/v1/projects/test-project-402417/global/addresses/psa-range].

student@cloudshell:~ (test-project-402417)$ gcloud services vpc-peerings connect \
    --service=servicenetworking.googleapis.com \
    --ranges=psa-range \
    --network=default
Operation "operations/pssn.p24-4470404856-595e209f-19b7-4669-8a71-cbd45de8ba66" finished successfully.

student@cloudshell:~ (test-project-402417)$

AlloyDB クラスタを作成する

us-central1 リージョンに AlloyDB クラスタを作成します。

postgres ユーザーのパスワードを定義します。独自のパスワードを定義することも、ランダム関数を使用してパスワードを生成することもできます。

export PGPASSWORD=`openssl rand -hex 12`

想定されるコンソール出力:

student@cloudshell:~ (test-project-402417)$ export PGPASSWORD=`openssl rand -hex 12`

後で使用できるように PostgreSQL のパスワードをメモしておきます。

echo $PGPASSWORD

想定されるコンソール出力:

student@cloudshell:~ (test-project-402417)$ echo $PGPASSWORD
bbefbfde7601985b0dee5723

リージョンと AlloyDB クラスタ名を定義します。リージョンは us-central1、クラスタ名は alloydb-aip-01 を使用します。

export REGION=us-central1
export ADBCLUSTER=alloydb-aip-01

コマンドを実行してクラスタを作成します。

gcloud alloydb clusters create $ADBCLUSTER \
    --password=$PGPASSWORD \
    --network=default \
    --region=$REGION

想定されるコンソール出力:

export REGION=us-central1
export ADBCLUSTER=alloydb-aip-01
gcloud alloydb clusters create $ADBCLUSTER \
    --password=$PGPASSWORD \
    --network=default \
    --region=$REGION
Operation ID: operation-1697655441138-6080235852277-9e7f04f5-2012fce4
Creating cluster...done.                                                                                                                                                                                                                                                           

AlloyDB プライマリ インスタンスを作成する

同じ Cloud Shell セッションで、クラスタの AlloyDB プライマリ インスタンスを作成します。切断した場合は、リージョンとクラスタ名の環境変数を再度定義する必要があります。

gcloud alloydb instances create $ADBCLUSTER-pr \
    --instance-type=PRIMARY \
    --cpu-count=2 \
    --region=$REGION \
    --cluster=$ADBCLUSTER

想定されるコンソール出力:

student@cloudshell:~ (test-project-402417)$ gcloud alloydb instances create $ADBCLUSTER-pr \
    --instance-type=PRIMARY \
    --cpu-count=2 \
    --region=$REGION \
    --availability-type ZONAL \
    --cluster=$ADBCLUSTER
Operation ID: operation-1697659203545-6080315c6e8ee-391805db-25852721
Creating instance...done.                                                                                                                                                                                                                                                     

5. AlloyDB に接続する

AlloyDB はプライベート専用接続を使用してデプロイされるため、データベースを操作するには PostgreSQL クライアントがインストールされた VM が必要です。

GCE VM をデプロイする

AlloyDB クラスタと同じリージョンと VPC に GCE VM を作成します。

Cloud Shell で、次のコマンドを実行します。

export ZONE=us-central1-a
gcloud compute instances create instance-1 \
    --zone=$ZONE \
    --create-disk=auto-delete=yes,boot=yes,image=projects/debian-cloud/global/images/$(gcloud compute images list --filter="family=debian-12 AND family!=debian-12-arm64" --format="value(name)") \
    --scopes=https://www.googleapis.com/auth/cloud-platform

想定されるコンソール出力:

student@cloudshell:~ (test-project-402417)$ export ZONE=us-central1-a
student@cloudshell:~ (test-project-402417)$ export ZONE=us-central1-a
gcloud compute instances create instance-1 \
    --zone=$ZONE \
    --create-disk=auto-delete=yes,boot=yes,image=projects/debian-cloud/global/images/$(gcloud compute images list --filter="family=debian-12 AND family!=debian-12-arm64" --format="value(name)") \
    --scopes=https://www.googleapis.com/auth/cloud-platform

Created [https://www.googleapis.com/compute/v1/projects/test-project-402417/zones/us-central1-a/instances/instance-1].
NAME: instance-1
ZONE: us-central1-a
MACHINE_TYPE: n1-standard-1
PREEMPTIBLE: 
INTERNAL_IP: 10.128.0.2
EXTERNAL_IP: 34.71.192.233
STATUS: RUNNING

Postgres クライアントをインストールする

デプロイされた VM に PostgreSQL クライアント ソフトウェアをインストールします。

VM に接続します。

gcloud compute ssh instance-1 --zone=us-central1-a

想定されるコンソール出力:

student@cloudshell:~ (test-project-402417)$ gcloud compute ssh instance-1 --zone=us-central1-a
Updating project ssh metadata...working..Updated [https://www.googleapis.com/compute/v1/projects/test-project-402417].                                                                                                                                                         
Updating project ssh metadata...done.                                                                                                                                                                                                                                              
Waiting for SSH key to propagate.
Warning: Permanently added 'compute.5110295539541121102' (ECDSA) to the list of known hosts.
Linux instance-1.us-central1-a.c.gleb-test-short-001-418811.internal 6.1.0-18-cloud-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.76-1 (2024-02-01) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
student@instance-1:~$ 

VM 内でソフトウェア実行コマンドをインストールします。

sudo apt-get update
sudo apt-get install --yes postgresql-client

想定されるコンソール出力:

student@instance-1:~$ sudo apt-get update
sudo apt-get install --yes postgresql-client
Get:1 https://packages.cloud.google.com/apt google-compute-engine-bullseye-stable InRelease [5146 B]
Get:2 https://packages.cloud.google.com/apt cloud-sdk-bullseye InRelease [6406 B]   
Hit:3 https://deb.debian.org/debian bullseye InRelease  
Get:4 https://deb.debian.org/debian-security bullseye-security InRelease [48.4 kB]
Get:5 https://packages.cloud.google.com/apt google-compute-engine-bullseye-stable/main amd64 Packages [1930 B]
Get:6 https://deb.debian.org/debian bullseye-updates InRelease [44.1 kB]
Get:7 https://deb.debian.org/debian bullseye-backports InRelease [49.0 kB]
...redacted...
update-alternatives: using /usr/share/postgresql/13/man/man1/psql.1.gz to provide /usr/share/man/man1/psql.1.gz (psql.1.gz) in auto mode
Setting up postgresql-client (13+225) ...
Processing triggers for man-db (2.9.4-2) ...
Processing triggers for libc-bin (2.31-13+deb11u7) ...

インスタンスに接続する

psql を使用して VM からプライマリ インスタンスに接続します。

インスタンス 1 VM への SSH セッションが開いている同じ Cloud Shell タブで、

メモした AlloyDB パスワード(PGPASSWORD)値と AlloyDB クラスタ ID を使用して、GCE VM から AlloyDB に接続します。

export PGPASSWORD=<Noted password>
export PROJECT_ID=$(gcloud config get-value project)
export REGION=us-central1
export ADBCLUSTER=alloydb-aip-01
export INSTANCE_IP=$(gcloud alloydb instances describe $ADBCLUSTER-pr --cluster=$ADBCLUSTER --region=$REGION --format="value(ipAddress)")
psql "host=$INSTANCE_IP user=postgres sslmode=require"

想定されるコンソール出力:

student@instance-1:~$ export PGPASSWORD=CQhOi5OygD4ps6ty
student@instance-1:~$ ADBCLUSTER=alloydb-aip-01
student@instance-1:~$ REGION=us-central1
student@instance-1:~$ INSTANCE_IP=$(gcloud alloydb instances describe $ADBCLUSTER-pr --cluster=$ADBCLUSTER --region=$REGION --format="value(ipAddress)")
gleb@instance-1:~$ psql "host=$INSTANCE_IP user=postgres sslmode=require"
psql (15.6 (Debian 15.6-0+deb12u1), server 15.5)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)
Type "help" for help.

postgres=>

psql セッションを閉じます。

exit

6. データベースを準備する

データベースを作成し、Vertex AI との統合を有効にして、データベース オブジェクトを作成し、データをインポートする必要があります。

AlloyDB に必要な権限を付与する

AlloyDB サービス エージェントに Vertex AI 権限を追加します。

上部の「+」記号を選択して、別の Cloud Shell タブを開きます。

4ca978f5142bb6ce.png

新しい 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"

想定されるコンソール出力:

student@cloudshell:~ (test-project-001-402417)$ PROJECT_ID=$(gcloud config get-value project)
Your active configuration is: [cloudshell-11039]
student@cloudshell:~ (test-project-001-402417)$ 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"
Updated IAM policy for project [test-project-001-402417].
bindings:
- members:
  - serviceAccount:service-4470404856@gcp-sa-alloydb.iam.gserviceaccount.com
  role: roles/aiplatform.user
- members:
...
etag: BwYIEbe_Z3U=
version: 1
 

タブに実行コマンド「exit」を入力して、タブを閉じます。

exit

データベースを作成する

データベース作成のクイックスタート。

GCE VM セッションで、次のコマンドを実行します。

データベースを作成します。

psql "host=$INSTANCE_IP user=postgres" -c "CREATE DATABASE quickstart_db"

想定されるコンソール出力:

student@instance-1:~$ psql "host=$INSTANCE_IP user=postgres" -c "CREATE DATABASE quickstart_db"
CREATE DATABASE
student@instance-1:~$  

Vertex AI インテグレーションを有効にする

Vertex AI インテグレーションとデータベースの pgvector 拡張機能を有効にします。

GCE VM で次のコマンドを実行します。

psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE"
psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "CREATE EXTENSION IF NOT EXISTS vector"

想定されるコンソール出力:

student@instance-1:~$ psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE"
psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "CREATE EXTENSION IF NOT EXISTS vector"
CREATE EXTENSION
CREATE EXTENSION
student@instance-1:~$ 

データをインポートする

準備したデータをダウンロードして、新しいデータベースにインポートします。

GCE VM で次のコマンドを実行します。

gsutil cat gs://cloud-training/gcc/gcc-tech-004/cymbal_demo_schema.sql |psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db"
gsutil cat gs://cloud-training/gcc/gcc-tech-004/cymbal_products.csv |psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "\copy cymbal_products from stdin csv header"
gsutil cat gs://cloud-training/gcc/gcc-tech-004/cymbal_inventory.csv |psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "\copy cymbal_inventory from stdin csv header"
gsutil cat gs://cloud-training/gcc/gcc-tech-004/cymbal_stores.csv |psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "\copy cymbal_stores from stdin csv header"

想定されるコンソール出力:

student@instance-1:~$ gsutil cat gs://cloud-training/gcc/gcc-tech-004/cymbal_demo_schema.sql |psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db"
SET
SET
SET
SET
SET
 set_config 
------------
 
(1 row)
SET
SET
SET
SET
SET
SET
CREATE TABLE
ALTER TABLE
CREATE TABLE
ALTER TABLE
CREATE TABLE
ALTER TABLE
CREATE TABLE
ALTER TABLE
CREATE SEQUENCE
ALTER TABLE
ALTER SEQUENCE
ALTER TABLE
ALTER TABLE
ALTER TABLE
student@instance-1:~$ gsutil cat gs://cloud-training/gcc/gcc-tech-004/cymbal_products.csv |psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "\copy cymbal_products from stdin csv header"
COPY 941
student@instance-1:~$ gsutil cat gs://cloud-training/gcc/gcc-tech-004/cymbal_inventory.csv |psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "\copy cymbal_inventory from stdin csv header"
COPY 263861
student@instance-1:~$ gsutil cat gs://cloud-training/gcc/gcc-tech-004/cymbal_stores.csv |psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db" -c "\copy cymbal_stores from stdin csv header"
COPY 4654
student@instance-1:~$

7. エンベディングを計算する

データをインポートすると、商品データが cymbal_products テーブルに、各店舗で購入可能な商品数を示す在庫データが cymbal_inventory テーブルに、店舗のリストが cymbal_stores テーブルに格納されます。商品の説明に基づいてベクトルデータを計算する必要があります。そのために、エンベディング関数を使用します。この関数を使用して、Vertex AI インテグレーションを使用して商品の説明に基づいてベクトルデータを計算し、テーブルに追加します。使用されているテクノロジーの詳細については、ドキュメントをご覧ください。

エンベディング列を作成する

psql を使用してデータベースに接続し、cymbal_products テーブルのエンベディング関数を使用してベクトルデータを含む仮想列を作成します。エンベディング関数は、product_description 列から提供されたデータに基づいて Vertex AI からベクトルデータを返します。

psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db"

データベースに接続した後、psql セッションで次のコマンドを実行します。

ALTER TABLE cymbal_products ADD COLUMN embedding vector(768) GENERATED ALWAYS AS (embedding('text-embedding-004',product_description)) STORED;

このコマンドを実行すると、仮想列が作成され、ベクトルデータが入力されます。

想定されるコンソール出力:

student@instance-1:~$ psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db"
psql (13.11 (Debian 13.11-0+deb11u1), server 14.7)
WARNING: psql major version 13, server major version 14.
         Some psql features might not work.
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.

quickstart_db=> ALTER TABLE cymbal_products ADD COLUMN embedding vector(768) GENERATED ALWAYS AS (embedding('text-embedding-004',product_description)) STORED;
ALTER TABLE
quickstart_db=> 

8. 類似検索を実行する

これで、説明に対して計算されたベクトル値と、リクエストで取得したベクトル値に基づいて、類似性検索を使用して検索を実行できるようになりました。

SQL クエリは、同じ psql コマンドライン インターフェースから実行できます。または、AlloyDB Studio から実行することもできます。マルチ行と複雑な出力は、AlloyDB Studio で表示すると見やすくなります。

AlloyDB Studio に接続する

以降の章では、データベースへの接続を必要とするすべての SQL コマンドを AlloyDB Studio で実行することもできます。コマンドを実行するには、プライマリ インスタンスをクリックして AlloyDB クラスタのウェブ コンソール インターフェースを開く必要があります。

ef4bfbcf0ed2ef3a.png

次に、左側の AlloyDB Studio をクリックします。

5c155cbcd7d43a1.png

quickstart_db データベースとユーザー postgres を選択し、クラスタの作成時にメモしたパスワードを指定します。次に、[Authenticate] ボタンをクリックします。

432613065cac864f.png

AlloyDB Studio インターフェースが開きます。データベースでコマンドを実行するには、右側の [Editor 1] タブをクリックします。

b36c28f8165119ca.png

SQL コマンドを実行できるインターフェースが開きます。

cf43aa20f292797e.png

コマンドライン psql を使用する場合は、前章で説明したように、別の方法で VM SSH セッションからデータベースに接続します。

psql から類似検索を実行する

データベース セッションが切断された場合は、psql または AlloyDB Studio を使用してデータベースに再度接続します。

データベースに接続します。

psql "host=$INSTANCE_IP user=postgres dbname=quickstart_db"

クエリを実行して、クライアントのリクエストに最も関連性の高い利用可能なプロダクトのリストを取得します。ベクトル値を取得するために Vertex AI に渡すリクエストは、「この地域でよく育つ果樹は何ですか?」というようなものです。

リクエストに最も適した最初の 10 個のアイテムを選択するために実行できるクエリは次のとおりです。

SELECT
        cp.product_name,
        left(cp.product_description,80) as description,
        cp.sale_price,
        cs.zip_code,
        (cp.embedding <=> embedding('text-embedding-004','What kind of fruit trees grow well here?')::vector) as distance
FROM
        cymbal_products cp
JOIN cymbal_inventory ci on
        ci.uniq_id=cp.uniq_id
JOIN cymbal_stores cs on
        cs.store_id=ci.store_id
        AND ci.inventory>0
        AND cs.store_id = 1583
ORDER BY
        distance ASC
LIMIT 10;

想定される出力は次のとおりです。

quickstart_db=> SELECT
        cp.product_name,
        left(cp.product_description,80) as description,
        cp.sale_price,
        cs.zip_code,
        (cp.embedding <=> embedding('text-embedding-004','What kind of fruit trees grow well here?')::vector) as distance
FROM
        cymbal_products cp
JOIN cymbal_inventory ci on
        ci.uniq_id=cp.uniq_id
JOIN cymbal_stores cs on
        cs.store_id=ci.store_id
        AND ci.inventory>0
        AND cs.store_id = 1583
ORDER BY
        distance ASC
LIMIT 10;
      product_name       |                                   description                                    | sale_price | zip_code |      distance       
-------------------------+----------------------------------------------------------------------------------+------------+----------+---------------------
 Cherry Tree             | This is a beautiful cherry tree that will produce delicious cherries. It is an d |      75.00 |    93230 | 0.43922018972266397
 Meyer Lemon Tree        | Meyer Lemon trees are California's favorite lemon tree! Grow your own lemons by  |         34 |    93230 |  0.4685112926118228
 Toyon                   | This is a beautiful toyon tree that can grow to be over 20 feet tall. It is an e |      10.00 |    93230 |  0.4835677149651668
 California Lilac        | This is a beautiful lilac tree that can grow to be over 10 feet tall. It is an d |       5.00 |    93230 |  0.4947204525907498
 California Peppertree   | This is a beautiful peppertree that can grow to be over 30 feet tall. It is an e |      25.00 |    93230 |  0.5054166905547247
 California Black Walnut | This is a beautiful walnut tree that can grow to be over 80 feet tall. It is a d |     100.00 |    93230 |  0.5084219510932597
 California Sycamore     | This is a beautiful sycamore tree that can grow to be over 100 feet tall. It is  |     300.00 |    93230 |  0.5140519790508755
 Coast Live Oak          | This is a beautiful oak tree that can grow to be over 100 feet tall. It is an ev |     500.00 |    93230 |  0.5143126438081371
 Fremont Cottonwood      | This is a beautiful cottonwood tree that can grow to be over 100 feet tall. It i |     200.00 |    93230 |  0.5174774727252058
 Madrone                 | This is a beautiful madrona tree that can grow to be over 80 feet tall. It is an |      50.00 |    93230 |  0.5227400803389093

9. 対応を改善する

クエリの結果を使用してクライアント アプリケーションへのレスポンスを改善し、Vertex AI 生成基盤言語モデルへのプロンプトの一部として提供されたクエリ結果を使用して有意な出力を準備できます。

これを実現するために、ベクトル検索の結果を含む JSON を生成します。生成された JSON を Vertex AI のテキスト LLM モデルのプロンプトに追加して、有意な出力を作成します。最初のステップでは JSON を生成してから Vertex AI Studio でテストし、最後のステップではアプリケーションで使用できる SQL ステートメントに組み込みます。

JSON 形式で出力を生成する

クエリを変更して、出力を JSON 形式で生成し、Vertex AI に渡す行を 1 つだけ返します。

クエリの例を次に示します。

WITH trees as (
SELECT
        cp.product_name,
        left(cp.product_description,80) as description,
        cp.sale_price,
        cs.zip_code,
        cp.uniq_id as product_id
FROM
        cymbal_products cp
JOIN cymbal_inventory ci on
        ci.uniq_id=cp.uniq_id
JOIN cymbal_stores cs on
        cs.store_id=ci.store_id
        AND ci.inventory>0
        AND cs.store_id = 1583
ORDER BY
        (cp.embedding <=> embedding('text-embedding-004','What kind of fruit trees grow well here?')::vector) ASC
LIMIT 1)
SELECT json_agg(trees) FROM trees;

出力に期待される JSON は次のとおりです。

[{"product_name":"Cherry Tree","description":"This is a beautiful cherry tree that will produce delicious cherries. It is an d","sale_price":75.00,"zip_code":93230,"product_id":"d536e9e823296a2eba198e52dd23e712"}]

Vertex AI Studio でプロンプトを実行する

生成された JSON を使用して、Vertex AI Studio の生成 AI テキストモデルにプロンプトの一部として提供できます。

Cloud コンソールで Vertex AI Studio を開きます。

e514b176aef7945e.png

54712e5ade7121f.png

追加の API を有効にするよう求められる場合があります。このリクエストは無視できます。ラボを完了するために追加の API は必要ありません。

使用するプロンプトは次のとおりです。

お客様のニーズに基づいて商品を見つける手助けをする、親しみやすいアドバイザーです。

クライアントのリクエストに基づいて、検索内容に関連性の高い商品のリストを読み込みました。

{"product_name":"name","description":"some description","sale_price":10,"zip_code": 10234, "produt_id": "02056727942aeb714dc9a2313654e1b0"} などの値のリストを含む JSON 形式のリスト

対象となるプロダクトは次のとおりです。

[JSON の場所]

お客様から「この地域で育ちやすい木は何ですか?」と質問された場合

「商品、価格、補足情報についての情報を提供してもらう必要があります」というメッセージが表示されます。

JSON 値を使用して gemini-1.5-flash モデルを使用してプロンプトを実行した場合の結果は次のとおりです。

30e5072cd2975685.png

この例でモデルから得られた回答は次のとおりです。モデルとパラメータは時間の経過とともに変化するため、回答が異なる場合があります。

「お住まいの地域で育つ木をお探しとのことですね。郵便番号 93230 に基づいて、Cherry Tree が最適なようです。

おいしいチェリーをつける美しい木として描かれています。現在、$75.00 のセール価格です。

地域ごとの成長率については詳しくありませんが、一般的にサクラは水はけの良い土壌と日当たりの良い場所を好みます。

最良の結果を得るには、地域のナーサリーやガーデニングの専門家に相談することをおすすめします。地域や土壌の状態に応じたアドバイスをもらえるはずです。また、ニーズに合った品種の選択や、植え付けと手入れに関するヒントも提供しています。」

PSQL でプロンプトを実行する

AlloyDB AI と Vertex AI の統合を使用すると、データベースで SQL を直接使用して生成モデルから同じレスポンスを取得できます。ただし、gemini-1.5-flash モデルを使用するには、まずモデルを登録する必要があります。

拡張機能をバージョン 1.4.1 にアップグレードします(現在のバージョンがそれより前の場合)。前述のように psql から quickstart_db データベースに接続するか(または AlloyDB Studio を使用)、次のコマンドを実行します。

SELECT extversion from pg_extension where extname='google_ml_integration';

返された値が 1.4.1 未満の場合は、次のコマンドを実行します。

ALTER EXTENSION google_ml_integration UPDATE TO '1.4.1';

次に、google_ml_integration.enable_model_support データベース フラグを「on」に設定する必要があります。これを行うには、AlloyDB ウェブ コンソール インターフェースを使用するか、次の gcloud コマンドを実行します。

PROJECT_ID=$(gcloud config get-value project)
REGION=us-central1
ADBCLUSTER=alloydb-aip-01
gcloud beta alloydb instances update $ADBCLUSTER-pr \
  --database-flags google_ml_integration.enable_model_support=on \
  --region=$REGION \
  --cluster=$ADBCLUSTER \
  --project=$PROJECT_ID \
  --update-mode=FORCE_APPLY

このコマンドがバックグラウンドで実行されるまでに 3 ~ 5 分ほどかかります。その後、psql セッションで新しいフラグを検証するか、AlloyDB Studio を使用して quickstart_db データベースに接続します。

show google_ml_integration.enable_model_support;

psql セッションからの想定される出力は「on」です。

postgres=> show google_ml_integration.enable_model_support;
 google_ml_integration.enable_model_support 
--------------------------------------------
 on
(1 row)

次に、2 つのモデルを登録する必要があります。1 つ目は、すでに使用されている text-embedding-004 モデルです。モデル登録機能を有効にしたため、登録する必要があります。

psql または AlloyDB Studio でモデル実行を登録するには、次のコードを使用します。

CALL
  google_ml.create_model(
    model_id => 'text-embedding-004',
    model_provider => 'google',
    model_qualified_name => 'text-embedding-004',
    model_type => 'text_embedding',
    model_auth_type => 'alloydb_service_agent_iam',
    model_in_transform_fn => 'google_ml.vertexai_text_embedding_input_transform',
    model_out_transform_fn => 'google_ml.vertexai_text_embedding_output_transform');

次に登録するモデルは gemini-1.5-flash-002 です。これは、ユーザー フレンドリーな出力の生成に使用されます。

CALL
  google_ml.create_model(
    model_id => 'gemini-1.5-flash-002',
    model_request_url => 'https://$REGION-aiplatform.googleapis.com/v1/projects/$PROJECT_ID/locations/$REGION/publishers/google/models/gemini-1.5-flash-002:streamGenerateContent',
    model_provider => 'google',
    model_auth_type => 'alloydb_service_agent_iam');

登録済みのモデルのリストは、google_ml.model_info_view から情報を選択することでいつでも確認できます。

select model_id,model_type from google_ml.model_info_view;

出力例を次に示します。

quickstart_db=> select model_id,model_type from google_ml.model_info_view;
        model_id         |   model_type   
-------------------------+----------------
 textembedding-gecko     | text_embedding
 textembedding-gecko@001 | text_embedding
 text-embedding-004      | text_embedding
 gemini-1.5-flash-001    | generic
(4 rows)

サブクエリで生成された JSON を使用して、SQL を使用して生成 AI テキストモデルにプロンプトの一部として提供できます。

データベースへの psql または AlloyDB Studio セッションでクエリを実行します。

WITH trees AS (
SELECT
        cp.product_name,
        cp.product_description AS description,
        cp.sale_price,
        cs.zip_code,
        cp.uniq_id AS product_id
FROM
        cymbal_products cp
JOIN cymbal_inventory ci ON
        ci.uniq_id = cp.uniq_id
JOIN cymbal_stores cs ON
        cs.store_id = ci.store_id
        AND ci.inventory>0
        AND cs.store_id = 1583
ORDER BY
        (cp.embedding <=> embedding('text-embedding-004',
        'What kind of fruit trees grow well here?')::vector) ASC
LIMIT 1),
prompt AS (
SELECT
        'You are a friendly advisor helping to find a product based on the customer''s needs.
Based on the client request we have loaded a list of products closely related to search.
The list in JSON format with list of values like {"product_name":"name","product_description":"some description","sale_price":10}
Here is the list of products:' || json_agg(trees) || 'The customer asked "What kind of fruit trees grow well here?"
You should give information about the product, price and some supplemental information' AS prompt_text
FROM
        trees),
response AS (
SELECT
        json_array_elements(google_ml.predict_row( model_id =>'gemini-1.5-flash-002',
        request_body => json_build_object('contents',
        json_build_object('role',
        'user',
        'parts',
        json_build_object('text',
        prompt_text)))))->'candidates'->0->'content'->'parts'->0->'text' AS resp
FROM
        prompt)
SELECT
        string_agg(resp::text,
        ' ')
FROM
        response;

想定される出力は次のとおりです。出力は、モデルのバージョンとパラメータによって異なる場合があります。

"That" "'s a great question! Based on your location (assuming you're" " in zip code 93230), I have a suggestion for a" " fruit tree that should thrive.\n\nWe have the **Cherry Tree** available.\n\n**Product Name:** Cherry Tree\n\n**Description:** This is a beautiful cherry" " tree that will produce delicious cherries. It's a deciduous tree (meaning it loses its leaves in the fall) growing to about 15 feet tall." " The leaves are dark green in summer, turning a beautiful red in the fall. Cherry trees are known for their beauty, shade, and privacy.\n\n**Sale Price:** $75.00\n\n**Important Considerations for Growing" " Cherry Trees:**\n\n* **Climate:** Cherry trees prefer a cool, moist climate, and 93230 falls within a suitable range (USDA zones 4-9). However, it's always a good idea to" " check the specific microclimate of your property (sun exposure, drainage etc.).\n* **Soil:** They do best in sandy soil. If your soil is different, you may need to amend it to improve drainage.\n* **Pollination:** Many cherry varieties require a second, compatible cherry tree for proper pollination" ". Check the specific pollination needs of this variety before purchase if you want a significant cherry yield.\n\nThis cherry tree is a beautiful addition to any yard and will provide you with delicious cherries if you can meet its needs. Would you like to know more about its pollination requirements, or perhaps see if we have any other" " fruit trees suitable for your area?\n" ""

10. ベクトル インデックスを作成する

Google のデータセットは非常に小さく、レスポンス時間は主に AI モデルとのやり取りに依存します。ただし、数百万ものベクトルがある場合、ベクトル検索部分がレスポンス時間の大部分を占め、システムに大きな負荷をかける可能性があります。これを改善するには、ベクトルの上にインデックスを構築します。

ScaNN インデックスを作成する

SCANN インデックスを作成するには、もう 1 つの拡張機能を有効にする必要があります。拡張機能 alloydb_scann は、Google ScaNN アルゴリズムを使用して ANN タイプのベクトル インデックスを操作するためのインターフェースを提供します。

CREATE EXTENSION IF NOT EXISTS alloydb_scann;

予想される出力:

quickstart_db=> CREATE EXTENSION IF NOT EXISTS alloydb_scann;
CREATE EXTENSION
Time: 27.468 ms
quickstart_db=> 

これでインデックスを作成できます。次の例では、ほとんどのパラメータをデフォルトのままにして、インデックスのパーティション数(num_leaves)のみを指定しています。

CREATE INDEX cymbal_products_embeddings_scann ON cymbal_products
  USING scann (embedding cosine)
  WITH (num_leaves=31, max_num_levels = 2);

インデックス パラメータのチューニングについては、ドキュメントをご覧ください。

予想される出力:

quickstart_db=> CREATE INDEX cymbal_products_embeddings_scann ON cymbal_products
  USING scann (embedding cosine)
  WITH (num_leaves=31, max_num_levels = 2);
CREATE INDEX
quickstart_db=>

レスポンスの比較

これで、EXPLAIN モードでベクトル検索クエリを実行し、インデックスが使用されたかどうかを確認できます。

EXPLAIN (analyze) 
WITH trees as (
SELECT
        cp.product_name,
        left(cp.product_description,80) as description,
        cp.sale_price,
        cs.zip_code,
        cp.uniq_id as product_id
FROM
        cymbal_products cp
JOIN cymbal_inventory ci on
        ci.uniq_id=cp.uniq_id
JOIN cymbal_stores cs on
        cs.store_id=ci.store_id
        AND ci.inventory>0
        AND cs.store_id = 1583
ORDER BY
        (cp.embedding <=> embedding('text-embedding-004','What kind of fruit trees grow well here?')::vector) ASC
LIMIT 1)
SELECT json_agg(trees) FROM trees;

予想される出力:

Aggregate (cost=16.59..16.60 rows=1 width=32) (actual time=2.875..2.877 rows=1 loops=1)
-> Subquery Scan on trees (cost=8.42..16.59 rows=1 width=142) (actual time=2.860..2.862 rows=1 loops=1)
-> Limit (cost=8.42..16.58 rows=1 width=158) (actual time=2.855..2.856 rows=1 loops=1)
-> Nested Loop (cost=8.42..6489.19 rows=794 width=158) (actual time=2.854..2.855 rows=1 loops=1)
-> Nested Loop (cost=8.13..6466.99 rows=794 width=938) (actual time=2.742..2.743 rows=1 loops=1)
-> Index Scan using cymbal_products_embeddings_scann on cymbal_products cp (cost=7.71..111.99 rows=876 width=934) (actual time=2.724..2.724 rows=1 loops=1)
Order By: (embedding <=> '[0.008864171,0.03693164,-0.024245683,-0.00355923,0.0055611245,0.015985578,...<redacted>...5685,-0.03914233,-0.018452475,0.00826032,-0.07372604]'::vector)
-> Index Scan using walmart_inventory_pkey on cymbal_inventory ci (cost=0.42..7.26 rows=1 width=37) (actual time=0.015..0.015 rows=1 loops=1)
Index Cond: ((store_id = 1583) AND (uniq_id = (cp.uniq_id)::text))

出力から、クエリで「cymbal_products で cymbal_products_embeddings_scann を使用するインデックス スキャン」が使用されていることが明確にわかります。

explain なしでクエリを実行すると、次の結果が返されます。

WITH trees as (
SELECT
        cp.product_name,
        left(cp.product_description,80) as description,
        cp.sale_price,
        cs.zip_code,
        cp.uniq_id as product_id
FROM
        cymbal_products cp
JOIN cymbal_inventory ci on
        ci.uniq_id=cp.uniq_id
JOIN cymbal_stores cs on
        cs.store_id=ci.store_id
        AND ci.inventory>0
        AND cs.store_id = 1583
ORDER BY
        (cp.embedding <=> embedding('text-embedding-004','What kind of fruit trees grow well here?')::vector) ASC
LIMIT 1)
SELECT json_agg(trees) FROM trees;

予想される出力:

[{"product_name":"Meyer Lemon Tree","description":"Meyer Lemon trees are California's favorite lemon tree! Grow your own lemons by ","sale_price":34,"zip_code":93230,"product_id":"02056727942aeb714dc9a2313654e1b0"}]

結果が少し異なり、インデックスなしの検索で上位に表示されていたチェリー ツリーではなく、2 番目の選択肢であるマイヤーレモン ツリーが表示されています。インデックスはパフォーマンスを向上させますが、良好な結果を得るのに十分な精度を維持します。

ベクトル用に利用可能なさまざまなインデックスを試すことができます。また、ドキュメント ページで、Langchain 統合を使用したラボやサンプルをご確認ください。

11. 環境をクリーンアップする

ラボの終了時に AlloyDB インスタンスとクラスタを破棄します。

AlloyDB クラスタとすべてのインスタンスを削除する

クラスタは force オプションで破棄され、クラスタに属するすべてのインスタンスも削除されます。

接続が切断され、以前の設定がすべて失われた場合は、Cloud Shell でプロジェクトと環境変数を定義します。

gcloud config set project <your project id>
export REGION=us-central1
export ADBCLUSTER=alloydb-aip-01
export PROJECT_ID=$(gcloud config get-value project)

クラスタを削除します。

gcloud alloydb clusters delete $ADBCLUSTER --region=$REGION --force

想定されるコンソール出力:

student@cloudshell:~ (test-project-001-402417)$ gcloud alloydb clusters delete $ADBCLUSTER --region=$REGION --force
All of the cluster data will be lost when the cluster is deleted.

Do you want to continue (Y/n)?  Y

Operation ID: operation-1697820178429-6082890a0b570-4a72f7e4-4c5df36f
Deleting cluster...done.   

AlloyDB バックアップを削除する

クラスタの AlloyDB バックアップをすべて削除します。

for i in $(gcloud alloydb backups list --filter="CLUSTER_NAME: projects/$PROJECT_ID/locations/$REGION/clusters/$ADBCLUSTER" --format="value(name)" --sort-by=~createTime) ; do gcloud alloydb backups delete $(basename $i) --region $REGION --quiet; done

想定されるコンソール出力:

student@cloudshell:~ (test-project-001-402417)$ for i in $(gcloud alloydb backups list --filter="CLUSTER_NAME: projects/$PROJECT_ID/locations/$REGION/clusters/$ADBCLUSTER" --format="value(name)" --sort-by=~createTime) ; do gcloud alloydb backups delete $(basename $i) --region $REGION --quiet; done
Operation ID: operation-1697826266108-60829fb7b5258-7f99dc0b-99f3c35f
Deleting backup...done.                                                                                                                                                                                                                                                            

これで、VM を破棄できます。

GCE VM を削除する

Cloud Shell で、次のコマンドを実行します。

export GCEVM=instance-1
export ZONE=us-central1-a
gcloud compute instances delete $GCEVM \
    --zone=$ZONE \
    --quiet

想定されるコンソール出力:

student@cloudshell:~ (test-project-001-402417)$ export GCEVM=instance-1
export ZONE=us-central1-a
gcloud compute instances delete $GCEVM \
    --zone=$ZONE \
    --quiet
Deleted 

12. 完了

以上で、この Codelab は完了です。

学習した内容

  • AlloyDB クラスタとプライマリ インスタンスをデプロイする方法
  • Google Compute Engine VM から AlloyDB に接続する方法
  • データベースを作成し、AlloyDB AI を有効にする方法
  • データベースにデータを読み込む方法
  • AlloyDB で Vertex AI エンベディング モデルを使用する方法
  • Vertex AI 生成モデルを使用して結果を拡充する方法
  • ベクトル インデックスを使用してパフォーマンスを改善する方法

13. アンケート

出力:

このチュートリアルをどのように使用されますか?

全体を通して読むだけ 内容を読んで演習をやり遂げる