1. 簡介
在本程式碼研究室中,您將瞭解如何在 GKE 上部署 AlloyDB Omni,並搭配在同一 Kubernetes 叢集中部署的開放式嵌入模型使用。在相同 GKE 叢集中,將模型部署在資料庫執行個體旁,可減少延遲時間,並減少對第三方服務的依賴。此外,如果資料不得離開機構,且不允許使用第三方服務,安全性規定可能會要求使用這個選項。
必要條件
- 具備 Google Cloud 控制台的基本知識
- 指令列介面和 Cloud Shell 的基本技能
課程內容
- 如何在 Google Kubernetes 叢集中部署 AlloyDB Omni
- 如何連線至 AlloyDB Omni
- 如何將資料載入 AlloyDB Omni
- 如何將開放式嵌入模型部署至 GKE
- 如何在 AlloyDB Omni 中註冊嵌入模型
- 如何為語意搜尋產生嵌入
- 如何在 AlloyDB Omni 中使用產生的嵌入項目進行語意搜尋
- 如何在 AlloyDB 中建立及使用向量索引
軟硬體需求
- Google Cloud 帳戶和 Google Cloud 專案
- 支援 Google Cloud 控制台和 Cloud Shell 的網路瀏覽器,例如 Chrome
2. 設定和需求
自助式環境設定
- 登入 Google Cloud 控制台,然後建立新專案或重複使用現有專案。如果您還沒有 Gmail 或 Google Workspace 帳戶,請務必建立帳戶。
- 「專案名稱」是這個專案參與者的顯示名稱。這是 Google API 不會使用的字元字串。您隨時可以更新。
- 專案 ID 在所有 Google Cloud 專案中都是不重複的值,且無法變更 (設定後即無法變更)。Cloud 控制台會自動產生唯一字串,您通常不需要理會這個字串。在大多數程式碼研究室中,您需要參照專案 ID (通常會標示為
PROJECT_ID
)。如果您不喜歡產生的 ID,可以產生另一個隨機 ID。或者,您也可以自行嘗試,看看是否可用。這項設定在這個步驟後就無法變更,並會在整個專案期間維持不變。 - 提醒您,有些 API 會使用第三個值「專案編號」。如要進一步瞭解這三個值,請參閱說明文件。
- 接下來,您需要在 Cloud 控制台中啟用帳單功能,才能使用 Cloud 資源/API。執行這個程式碼研究室不會產生太多費用,甚至可能完全不會產生費用。如要關閉資源,避免在本教學課程結束後繼續產生費用,您可以刪除建立的資源或專案。Google Cloud 新使用者可享有 $300 美元的免費試用期。
啟動 Cloud Shell
雖然 Google Cloud 可透過筆記型電腦遠端操作,但在本程式碼研究室中,您將使用 Google Cloud Shell,這是在雲端運作的指令列環境。
在 Google Cloud 控制台中,按一下右上方工具列的 Cloud Shell 圖示:
佈建並連線至環境的作業需要一些時間才能完成。完成後,畫面應如下所示:
這個虛擬機器會載入您需要的所有開發工具。提供永久的 5 GB 主目錄,而且在 Google Cloud 中運作,可大幅提升網路效能和驗證功能。您可以在瀏覽器中完成本程式碼研究室的所有工作。您不需要安裝任何東西。
3. 事前準備
啟用 API
輸出:
在 Cloud Shell 中,確認專案 ID 已設定完畢:
PROJECT_ID=$(gcloud config get-value project)
echo $PROJECT_ID
如果 Cloud Shell 設定中未定義,請使用下列指令進行設定
export PROJECT_ID=<your project>
gcloud config set project $PROJECT_ID
啟用所有必要服務:
gcloud services enable compute.googleapis.com
gcloud services enable container.googleapis.com
預期的輸出內容:
student@cloudshell:~ (test-project-001-402417)$ PROJECT_ID=test-project-001-402417 student@cloudshell:~ (test-project-001-402417)$ gcloud config set project test-project-001-402417 Updated property [core/project]. student@cloudshell:~ (test-project-001-402417)$ gcloud services enable compute.googleapis.com gcloud services enable container.googleapis.com Operation "operations/acat.p2-4470404856-1f44ebd8-894e-4356-bea7-b84165a57442" finished successfully.
4. 在 GKE 上部署 AlloyDB Omni
如要在 GKE 上部署 AlloyDB Omni,我們需要按照 AlloyDB Omni 運算子需求中列出的規定準備 Kubernetes 叢集。
建立 GKE 叢集
我們需要部署標準 GKE 叢集,並設定足以部署 Pod 與 AlloyDB Omni 例項的集區。Omni 需要至少 2 個 CPU 和 8 GB RAM,並保留一些空間給作業員和監控服務。
設定部署作業的環境變數。
export PROJECT_ID=$(gcloud config get project)
export LOCATION=us-central1
export CLUSTER_NAME=alloydb-ai-gke
export MACHINE_TYPE=e2-standard-4
接著,我們會使用 gcloud 建立 GKE Standard 叢集。
gcloud container clusters create ${CLUSTER_NAME} \
--project=${PROJECT_ID} \
--region=${LOCATION} \
--workload-pool=${PROJECT_ID}.svc.id.goog \
--release-channel=rapid \
--machine-type=${MACHINE_TYPE} \
--num-nodes=1
預期的控制台輸出內容:
student@cloudshell:~ (gleb-test-short-001-415614)$ export PROJECT_ID=$(gcloud config get project) export LOCATION=us-central1 export CLUSTER_NAME=alloydb-ai-gke export MACHINE_TYPE=n2-highmem-2 Your active configuration is: [gleb-test-short-001-415614] student@cloudshell:~ (gleb-test-short-001-415614)$ gcloud container clusters create ${CLUSTER_NAME} \ --project=${PROJECT_ID} \ --region=${LOCATION} \ --workload-pool=${PROJECT_ID}.svc.id.goog \ --release-channel=rapid \ --machine-type=${MACHINE_TYPE} \ --num-nodes=1 Note: The Kubelet readonly port (10255) is now deprecated. Please update your workloads to use the recommended alternatives. See https://cloud.google.com/kubernetes-engine/docs/how-to/disable-kubelet-readonly-port for ways to check usage and for migration instructions. Note: Your Pod address range (`--cluster-ipv4-cidr`) can accommodate at most 1008 node(s). Creating cluster alloydb-ai-gke in us-central1.. NAME: omni01 ZONE: us-central1-a MACHINE_TYPE: e2-standard-4 PREEMPTIBLE: INTERNAL_IP: 10.128.0.3 EXTERNAL_IP: 35.232.157.123 STATUS: RUNNING student@cloudshell:~ (gleb-test-short-001-415614)$
準備叢集
我們需要安裝 cert-manager 服務等必要元件。我們可以按照說明文件中的步驟安裝 cert-manager
我們會使用 Kubernetes 指令列工具 kubectl,該工具已在 Cloud Shell 中安裝。使用這項工具前,我們需要取得叢集的憑證。
gcloud container clusters get-credentials ${CLUSTER_NAME} --region=${LOCATION}
我們現在可以使用 kubectl 安裝 cert-manager:
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.16.2/cert-manager.yaml
預期的控制台輸出內容(經過遮蓋):
student@cloudshell:~$ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.16.2/cert-manager.yaml namespace/cert-manager created customresourcedefinition.apiextensions.k8s.io/certificaterequests.cert-manager.io created customresourcedefinition.apiextensions.k8s.io/certificates.cert-manager.io created customresourcedefinition.apiextensions.k8s.io/challenges.acme.cert-manager.io created customresourcedefinition.apiextensions.k8s.io/clusterissuers.cert-manager.io created ... validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created
安裝 AlloyDB Omni
安裝 AlloyDB Omni 運算子可使用 Helm 公用程式安裝。
執行下列指令,安裝 AlloyDB Omni 運算子:
export GCS_BUCKET=alloydb-omni-operator
export HELM_PATH=$(gcloud storage cat gs://$GCS_BUCKET/latest)
export OPERATOR_VERSION="${HELM_PATH%%/*}"
gcloud storage cp gs://$GCS_BUCKET/$HELM_PATH ./ --recursive
helm install alloydbomni-operator alloydbomni-operator-${OPERATOR_VERSION}.tgz \
--create-namespace \
--namespace alloydb-omni-system \
--atomic \
--timeout 5m
預期的控制台輸出內容(經過遮蓋):
student@cloudshell:~$ gcloud storage cp gs://$GCS_BUCKET/$HELM_PATH ./ --recursive Copying gs://alloydb-omni-operator/1.2.0/alloydbomni-operator-1.2.0.tgz to file://./alloydbomni-operator-1.2.0.tgz Completed files 1/1 | 126.5kiB/126.5kiB student@cloudshell:~$ helm install alloydbomni-operator alloydbomni-operator-${OPERATOR_VERSION}.tgz \ > --create-namespace \ > --namespace alloydb-omni-system \ > --atomic \ > --timeout 5m NAME: alloydbomni-operator LAST DEPLOYED: Mon Jan 20 13:13:20 2025 NAMESPACE: alloydb-omni-system STATUS: deployed REVISION: 1 TEST SUITE: None student@cloudshell:~$
安裝 AlloyDB Omni 運算子後,我們就能繼續部署資料庫叢集。
以下是部署資訊清單的範例,其中已啟用 googleMLExtension 參數和內部 (私人) 負載平衡器:
apiVersion: v1
kind: Secret
metadata:
name: db-pw-my-omni
type: Opaque
data:
my-omni: "VmVyeVN0cm9uZ1Bhc3N3b3Jk"
---
apiVersion: alloydbomni.dbadmin.goog/v1
kind: DBCluster
metadata:
name: my-omni
spec:
databaseVersion: "15.7.0"
primarySpec:
adminUser:
passwordRef:
name: db-pw-my-omni
features:
googleMLExtension:
enabled: true
resources:
cpu: 1
memory: 8Gi
disks:
- name: DataDisk
size: 20Gi
storageClass: standard
dbLoadBalancerOptions:
annotations:
networking.gke.io/load-balancer-type: "internal"
allowExternalIncomingTraffic: true
密碼的密鑰值是密碼字詞「VeryStrongPassword」的 Base64 表示法。更可靠的方法是使用 Google 密鑰管理工具來儲存密碼值。如要進一步瞭解相關資訊,請參閱說明文件。
將資訊清單儲存為 my-omni.yaml,以便在下一個步驟中套用。如果您使用的是 Cloud Shell,請按一下終端機右上方的「Open Editor」(開啟編輯器) 按鈕,即可使用編輯器執行這項操作。
儲存檔案後,請按下「Open Terminal」按鈕,返回終端機。檔案名稱為 my-omni.yaml。
使用 kubectl 公用程式將 my-omni.yaml 資訊清單套用至叢集:
kubectl apply -f my-omni.yaml
預期的控制台輸出內容:
secret/db-pw-my-omni created dbcluster.alloydbomni.dbadmin.goog/my-omni created
使用 kubectl 公用程式檢查 my-omni 叢集狀態:
kubectl get dbclusters.alloydbomni.dbadmin.goog my-omni -n default
在部署期間,叢集會經歷不同的階段,最後應會結束於 DBClusterReady 狀態。
預期的控制台輸出內容:
$ kubectl get dbclusters.alloydbomni.dbadmin.goog my-omni -n default NAME PRIMARYENDPOINT PRIMARYPHASE DBCLUSTERPHASE HAREADYSTATUS HAREADYREASON my-omni 10.131.0.33 Ready DBClusterReady
連線至 AlloyDB Omni
使用 Kubernetes Pod 連線
叢集就緒後,我們就可以在 AlloyDB Omni 執行個體 Pod 上使用 PostgreSQL 用戶端二進位檔。我們會找出 pod ID,然後使用 kubectl 直接連線至 pod 並執行用戶端軟體。密碼為「VeryStrongPassword」,這是透過 my-omni.yaml 中的雜湊值設定:
DB_CLUSTER_NAME=my-omni
DB_CLUSTER_NAMESPACE=default
DBPOD=`kubectl get pod --selector=alloydbomni.internal.dbadmin.goog/dbcluster=$DB_CLUSTER_NAME,alloydbomni.internal.dbadmin.goog/task-type=database -n $DB_CLUSTER_NAMESPACE -o jsonpath='{.items[0].metadata.name}'`
kubectl exec -ti $DBPOD -n $DB_CLUSTER_NAMESPACE -c database -- psql -h localhost -U postgres
控制台輸出內容範例:
DB_CLUSTER_NAME=my-omni DB_CLUSTER_NAMESPACE=default DBPOD=`kubectl get pod --selector=alloydbomni.internal.dbadmin.goog/dbcluster=$DB_CLUSTER_NAME,alloydbomni.internal.dbadmin.goog/task-type=database -n $DB_CLUSTER_NAMESPACE -o jsonpath='{.items[0].metadata.name}'` kubectl exec -ti $DBPOD -n $DB_CLUSTER_NAMESPACE -c database -- psql -h localhost -U postgres Password for user postgres: psql (15.7) SSL connection (protocol: TLSv1.3, cipher: TLS_AES_128_GCM_SHA256, compression: off) Type "help" for help. postgres=#
5. 在 GKE 上部署 AI 模型
如要測試 AlloyDB Omni AI 與本機模型的整合,我們需要將模型部署至叢集。
為模型建立節點集區
如要執行模型,我們需要準備節點集區來執行推論。從效能角度來看,最佳做法是使用含有顯示加速器的資源池,並使用節點設定 (例如 g2-standard-8 搭配 L4 Nvidia 加速器)。
使用 L4 加速器建立節點集區:
export PROJECT_ID=$(gcloud config get project)
export LOCATION=us-central1
export CLUSTER_NAME=alloydb-ai-gke
gcloud container node-pools create gpupool \
--accelerator type=nvidia-l4,count=1,gpu-driver-version=latest \
--project=${PROJECT_ID} \
--location=${LOCATION} \
--node-locations=${LOCATION}-a \
--cluster=${CLUSTER_NAME} \
--machine-type=g2-standard-8 \
--num-nodes=1
預期的輸出內容:
student@cloudshell$ export PROJECT_ID=$(gcloud config get project) Your active configuration is: [pant] export LOCATION=us-central1 export CLUSTER_NAME=alloydb-ai-gke student@cloudshell$ gcloud container node-pools create gpupool \ > --accelerator type=nvidia-l4,count=1,gpu-driver-version=latest \ > --project=${PROJECT_ID} \ > --location=${LOCATION} \ > --node-locations=${LOCATION}-a \ > --cluster=${CLUSTER_NAME} \ > --machine-type=g2-standard-8 \ > --num-nodes=1 Note: Machines with GPUs have certain limitations which may affect your workflow. Learn more at https://cloud.google.com/kubernetes-engine/docs/how-to/gpus Note: Starting in GKE 1.30.1-gke.115600, if you don't specify a driver version, GKE installs the default GPU driver for your node's GKE version. Creating node pool gpupool...done. Created [https://container.googleapis.com/v1/projects/student-test-001/zones/us-central1/clusters/alloydb-ai-gke/nodePools/gpupool]. NAME MACHINE_TYPE DISK_SIZE_GB NODE_VERSION gpupool g2-standard-8 100 1.31.4-gke.1183000
準備部署資訊清單
如要部署模型,我們需要準備部署資訊清單。
我們使用 Hugging Face 的 BGE Base v1.5 嵌入模型。如要查看模型資訊卡,請按這裡。如要部署模型,我們可以使用 Hugging Face 提供的操作說明和 GitHub 的部署套件。
複製套件
git clone https://github.com/huggingface/Google-Cloud-Containers
編輯資訊清單,將 cloud.google.com/gke-accelerator 值替換為 nvidia-l4,並為資源新增限制。
vi Google-Cloud-Containers/examples/gke/tei-deployment/gpu-config/deployment.yaml
以下是修正後的資訊清單。
apiVersion: apps/v1
kind: Deployment
metadata:
name: tei-deployment
spec:
replicas: 1
selector:
matchLabels:
app: tei-server
template:
metadata:
labels:
app: tei-server
hf.co/model: Snowflake--snowflake-arctic-embed-m
hf.co/task: text-embeddings
spec:
containers:
- name: tei-container
image: us-docker.pkg.dev/deeplearning-platform-release/gcr.io/huggingface-text-embeddings-inference-cu122.1-4.ubuntu2204:latest
resources:
requests:
nvidia.com/gpu: 1
limits:
nvidia.com/gpu: 1
env:
- name: MODEL_ID
value: Snowflake/snowflake-arctic-embed-m
- name: NUM_SHARD
value: "1"
- name: PORT
value: "8080"
volumeMounts:
- mountPath: /dev/shm
name: dshm
- mountPath: /data
name: data
volumes:
- name: dshm
emptyDir:
medium: Memory
sizeLimit: 1Gi
- name: data
emptyDir: {}
nodeSelector:
cloud.google.com/gke-accelerator: nvidia-l4
部署模型
我們需要為部署作業準備服務帳戶和命名空間。
建立 Kubernetes 命名空間 hf-gke-namespace。
export NAMESPACE=hf-gke-namespace
kubectl create namespace $NAMESPACE
建立 Kubernetes 服務帳戶
export SERVICE_ACCOUNT=hf-gke-service-account
kubectl create serviceaccount $SERVICE_ACCOUNT --namespace $NAMESPACE
部署模型
kubectl apply -f Google-Cloud-Containers/examples/gke/tei-deployment/gpu-config
驗證部署作業
kubectl get pods
驗證模型服務
kubectl get service tei-service
應該會顯示執行中的服務類型 ClusterIP
輸出內容範例:
student@cloudshell$ kubectl get service tei-service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE tei-service ClusterIP 34.118.233.48 <none> 8080/TCP 10m
我們會將服務的 CLUSTER-IP 用作端點位址。模型嵌入功能可以透過 URI http://34.118.233.48:8080/embed 回應。您稍後在 AlloyDB Omni 中註冊模型時,就會使用這個名稱。
我們可以使用 kubectl port-forward 指令公開它來進行測試。
kubectl port-forward service/tei-service 8080:8080
通訊埠轉送作業會在一個 Cloud Shell 工作階段中執行,因此我們需要另一個工作階段來進行測試。
使用頂端的「+」符號開啟另一個 Cloud Shell 分頁。
並在新殼層工作階段中執行 curl 指令。
curl http://localhost:8080/embed \
-X POST \
-d '{"inputs":"Test"}' \
-H 'Content-Type: application/json'
它應會傳回向量陣列,如下列範例輸出內容所示 (經過遮蓋):
curl http://localhost:8080/embed \ > -X POST \ > -d '{"inputs":"Test"}' \ > -H 'Content-Type: application/json' [[-0.018975832,0.0071419072,0.06347208,0.022992613,0.014205903 ... -0.03677433,0.01636146,0.06731572]]
6. 在 AlloyDB Omni 中註冊模型
如要測試 AlloyDB Omni 如何與已部署的模型搭配運作,我們需要建立資料庫並註冊模型。
建立資料庫
建立 GCE VM 做為跳板,從用戶端 VM 連線至 AlloyDB Omni,然後建立資料庫。
我們需要跳板,因為 Omni 的 GKE 外部負載平衡器會使用私人 IP 位址從虛擬私有雲提供存取權,但不允許從虛擬私有雲外部連線。這項做法通常更安全,而且不會將資料庫執行個體公開至網際網路。請參閱圖表,以便瞭解詳情。
如要在 Cloud Shell 工作階段中建立 VM,請執行以下操作:
export ZONE=us-central1-a
gcloud compute instances create instance-1 \
--zone=$ZONE
在 Cloud Shell 中使用 kubectl 找出 AlloyDB Omni 端點 IP:
kubectl get dbclusters.alloydbomni.dbadmin.goog my-omni -n default
記下 PRIMARYENDPOINT。我們來看個例子
結果:
student@cloudshell:~$ kubectl get dbclusters.alloydbomni.dbadmin.goog my-omni -n default NAME PRIMARYENDPOINT PRIMARYPHASE DBCLUSTERPHASE HAREADYSTATUS HAREADYREASON my-omni 10.131.0.33 Ready DBClusterReady student@cloudshell:~$
10.131.0.33 是我們在範例中用來連線至 AlloyDB Omni 執行個體的 IP。
使用 gcloud 連線至 VM:
gcloud compute ssh instance-1 --zone=$ZONE
如果系統提示您產生 SSH 金鑰,請按照指示操作。如要進一步瞭解 SSH 連線,請參閱說明文件。
在 VM 的 SSH 工作階段中安裝 PostgreSQL 用戶端:
sudo apt-get update
sudo apt-get install --yes postgresql-client
匯出 AlloyDB Omni 負載平衡器 IP,如以下範例所示 (請將 IP 替換為您的負載平衡器 IP):
export INSTANCE_IP=10.131.0.33
連線至 AlloyDB Omni,密碼為「VeryStrongPassword」,這是透過 my-omni.yaml 中的雜湊值設定:
psql "host=$INSTANCE_IP user=postgres sslmode=require"
在建立的 psql 工作階段中執行:
create database demo;
結束工作階段並連線至資料庫示範 (或者,您也可以在同一個工作階段中執行「\c demo」)
psql "host=$INSTANCE_IP user=postgres sslmode=require dbname=demo"
建立轉換函式
對於第三方嵌入模型,我們需要建立轉換函數,將輸入和輸出格式轉換為模型和內部函數預期的格式。
以下是負責處理輸入內容的轉換函式:
-- Input Transform Function corresponding to the custom model endpoint
CREATE OR REPLACE FUNCTION tei_text_input_transform(model_id VARCHAR(100), input_text TEXT)
RETURNS JSON
LANGUAGE plpgsql
AS $$
DECLARE
transformed_input JSON;
model_qualified_name TEXT;
BEGIN
SELECT json_build_object('inputs', input_text, 'truncate', true)::JSON INTO transformed_input;
RETURN transformed_input;
END;
$$;
連線至示範資料庫時執行提供的程式碼,如範例輸出內容所示:
demo=# -- Input Transform Function corresponding to the custom model endpoint CREATE OR REPLACE FUNCTION tei_text_input_transform(model_id VARCHAR(100), input_text TEXT) RETURNS JSON LANGUAGE plpgsql AS $$ DECLARE transformed_input JSON; model_qualified_name TEXT; BEGIN SELECT json_build_object('inputs', input_text, 'truncate', true)::JSON INTO transformed_input; RETURN transformed_input; END; $$; CREATE FUNCTION demo=#
以下是將回應從模型轉換為實數陣列的輸出函式:
-- Output Transform Function corresponding to the custom model endpoint
CREATE OR REPLACE FUNCTION tei_text_output_transform(model_id VARCHAR(100), response_json JSON)
RETURNS REAL[]
LANGUAGE plpgsql
AS $$
DECLARE
transformed_output REAL[];
BEGIN
SELECT ARRAY(SELECT json_array_elements_text(response_json->0)) INTO transformed_output;
RETURN transformed_output;
END;
$$;
在同一個工作階段中執行:
demo=# -- Output Transform Function corresponding to the custom model endpoint CREATE OR REPLACE FUNCTION tei_text_output_transform(model_id VARCHAR(100), response_json JSON) RETURNS REAL[] LANGUAGE plpgsql AS $$ DECLARE transformed_output REAL[]; BEGIN SELECT ARRAY(SELECT json_array_elements_text(response_json->0)) INTO transformed_output; RETURN transformed_output; END; $$; CREATE FUNCTION demo=#
註冊模型
我們現在可以在資料庫中註冊模型。
以下是註冊名稱為 bge-base-1.5 的模型程序呼叫,請將 IP 34.118.233.48 替換為模型服務 IP 位址 (kubectl get service tei-service 的輸出內容):
CALL
google_ml.create_model(
model_id => 'bge-base-1.5',
model_request_url => 'http://34.118.233.48:8080/embed',
model_provider => 'custom',
model_type => 'text_embedding',
model_in_transform_fn => 'tei_text_input_transform',
model_out_transform_fn => 'tei_text_output_transform');
在連線至示範資料庫時執行提供的程式碼:
demo=# CALL google_ml.create_model( model_id => 'bge-base-1.5', model_request_url => 'http://34.118.233.48:8080/embed', model_provider => 'custom', model_type => 'text_embedding', model_in_transform_fn => 'tei_text_input_transform', model_out_transform_fn => 'tei_text_output_transform'); CALL demo=#
我們可以使用下列測試查詢來測試註冊模型,這項查詢應會傳回實數陣列。
select google_ml.embedding('bge-base-1.5','What is AlloyDB Omni?');
7. 在 AlloyDB Omni 中測試模型
載入資料
如要測試 AlloyDB Omni 如何與已部署的模型搭配運作,我們需要載入一些資料。我使用與 其他程式碼研究室中某個向量搜尋 AlloyDB 的資料相同。
您可以使用 Google Cloud SDK 和 PostgreSQL 用戶端軟體來載入資料。我們可以使用用來建立示範資料庫的相同用戶端 VM。如果您使用的是 VM 映像檔的預設值,Google Cloud SDK 應該已安裝在該處。不過,如果您使用自訂圖片而未使用 Google SDK,可以按照說明文件新增圖片。
匯出 AlloyDB Omni 負載平衡器 IP,如以下範例所示 (請將 IP 替換為您的負載平衡器 IP):
export INSTANCE_IP=10.131.0.33
連結至資料庫並啟用 pgvector 擴充功能。
psql "host=$INSTANCE_IP user=postgres sslmode=require dbname=demo"
在 psql 工作階段中:
CREATE EXTENSION IF NOT EXISTS vector;
請結束 psql 工作階段,然後在指令列工作階段中執行指令,將資料載入示範資料庫。
建立資料表:
gcloud storage cat gs://cloud-training/gcc/gcc-tech-004/cymbal_demo_schema.sql |psql "host=$INSTANCE_IP user=postgres dbname=demo"
預期的控制台輸出內容:
student@cloudshell:~$ gcloud storage cat gs://cloud-training/gcc/gcc-tech-004/cymbal_demo_schema.sql |psql "host=$INSTANCE_IP user=postgres dbname=demo" Password for user postgres: 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@cloudshell:~$
以下是已建立的資料表清單:
psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "\dt+"
輸出:
student@cloudshell:~$ psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "\dt+" Password for user postgres: List of relations Schema | Name | Type | Owner | Persistence | Access method | Size | Description --------+------------------+-------+----------+-------------+---------------+------------+------------- public | cymbal_embedding | table | postgres | permanent | heap | 8192 bytes | public | cymbal_inventory | table | postgres | permanent | heap | 8192 bytes | public | cymbal_products | table | postgres | permanent | heap | 8192 bytes | public | cymbal_stores | table | postgres | permanent | heap | 8192 bytes | (4 rows) student@cloudshell:~$
將資料載入 cymbal_products 資料表:
gcloud storage cat gs://cloud-training/gcc/gcc-tech-004/cymbal_products.csv |psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "\copy cymbal_products from stdin csv header"
預期的控制台輸出內容:
student@cloudshell:~$ gcloud storage cat gs://cloud-training/gcc/gcc-tech-004/cymbal_products.csv |psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "\copy cymbal_products from stdin csv header" COPY 941 student@cloudshell:~$
以下是 cymbal_products 資料表的幾個資料列範例。
psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "SELECT uniq_id,left(product_name,30),left(product_description,50),sale_price FROM cymbal_products limit 3"
輸出:
student@cloudshell:~$ psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "SELECT uniq_id,left(product_name,30),left(product_description,50),sale_price FROM cymbal_products limit 3" Password for user postgres: uniq_id | left | left | sale_price ----------------------------------+--------------------------------+----------------------------------------------------+------------ a73d5f754f225ecb9fdc64232a57bc37 | Laundry Tub Strainer Cup | Laundry tub strainer cup Chrome For 1-.50, drain | 11.74 41b8993891aa7d39352f092ace8f3a86 | LED Starry Star Night Light La | LED Starry Star Night Light Laser Projector 3D Oc | 46.97 ed4a5c1b02990a1bebec908d416fe801 | Surya Horizon HRZ-1060 Area Ru | The 100% polypropylene construction of the Surya | 77.4 (3 rows) student@cloudshell:~$
將資料載入 cymbal_inventory 資料表:
gcloud storage cat gs://cloud-training/gcc/gcc-tech-004/cymbal_inventory.csv |psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "\copy cymbal_inventory from stdin csv header"
預期的控制台輸出內容:
student@cloudshell:~$ gcloud storage cat gs://cloud-training/gcc/gcc-tech-004/cymbal_inventory.csv |psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "\copy cymbal_inventory from stdin csv header" Password for user postgres: COPY 263861 student@cloudshell:~$
以下是 cymbal_inventory 資料表的幾個資料列範例。
psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "SELECT * FROM cymbal_inventory LIMIT 3"
輸出:
student@cloudshell:~$ psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "SELECT * FROM cymbal_inventory LIMIT 3" Password for user postgres: store_id | uniq_id | inventory ----------+----------------------------------+----------- 1583 | adc4964a6138d1148b1d98c557546695 | 5 1490 | adc4964a6138d1148b1d98c557546695 | 4 1492 | adc4964a6138d1148b1d98c557546695 | 3 (3 rows) student@cloudshell:~$
將資料載入 cymbal_stores 資料表:
gcloud storage cat gs://cloud-training/gcc/gcc-tech-004/cymbal_stores.csv |psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "\copy cymbal_stores from stdin csv header"
預期的控制台輸出內容:
student@cloudshell:~$ gcloud storage cat gs://cloud-training/gcc/gcc-tech-004/cymbal_stores.csv |psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "\copy cymbal_stores from stdin csv header" Password for user postgres: COPY 4654 student@cloudshell:~$
以下是 cymbal_stores 資料表的幾個資料列範例。
psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "SELECT store_id, name, zip_code FROM cymbal_stores limit 3"
輸出:
student@cloudshell:~$ psql "host=$INSTANCE_IP user=postgres dbname=demo" -c "SELECT store_id, name, zip_code FROM cymbal_stores limit 3" Password for user postgres: store_id | name | zip_code ----------+-------------------+---------- 1990 | Mayaguez Store | 680 2267 | Ware Supercenter | 1082 4359 | Ponce Supercenter | 780 (3 rows) student@cloudshell:~$
建構嵌入
使用 psql 連線至示範資料庫,並根據產品名稱和說明,為 cymbal_products 資料表中描述的產品建立嵌入資料。
連線至示範資料庫:
psql "host=$INSTANCE_IP user=postgres sslmode=require dbname=demo"
我們使用含有欄嵌入功能的 cymbal_embedding 資料表來儲存嵌入資料,並將產品說明做為函式中的文字輸入內容。
啟用查詢的時間,以便日後與遠端模型進行比較:
\timing
執行查詢來建構嵌入:
INSERT INTO cymbal_embedding(uniq_id,embedding) SELECT uniq_id, google_ml.embedding('bge-base-1.5',product_description)::vector FROM cymbal_products;
預期的控制台輸出內容:
demo=# INSERT INTO cymbal_embedding(uniq_id,embedding) SELECT uniq_id, google_ml.embedding('bge-base-1.5',product_description)::vector FROM cymbal_products; INSERT 0 941 Time: 11069.762 ms (00:11.070) demo=#
在這個範例中,為 941 筆記錄建立嵌入資料大約需要 11 秒。
執行測試查詢
使用 psql 連線至示範資料庫,並啟用計時功能,以便測量查詢的執行時間,就像建立內嵌內容時一樣。
讓我們使用餘弦距離做為向量搜尋演算法,找出符合「這裡適合種植哪種果樹?」這類要求的前 5 項產品。
在 psql 工作階段中執行:
SELECT
cp.product_name,
left(cp.product_description,80) as description,
cp.sale_price,
cs.zip_code,
(ce.embedding <=> google_ml.embedding('bge-base-1.5','What kind of fruit trees grow well here?')::vector) as distance
FROM
cymbal_products cp
JOIN cymbal_embedding ce on
ce.uniq_id=cp.uniq_id
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 5;
預期的控制台輸出內容:
demo=# SELECT cp.product_name, left(cp.product_description,80) as description, cp.sale_price, cs.zip_code, (ce.embedding <=> google_ml.embedding('bge-base-1.5','What kind of fruit trees grow well here?')::vector) as distance FROM cymbal_products cp JOIN cymbal_embedding ce on ce.uniq_id=cp.uniq_id 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 5; product_name | description | sale_price | zip_code | distance -----------------------+----------------------------------------------------------------------------------+------------+----------+--------------------- California Sycamore | This is a beautiful sycamore tree that can grow to be over 100 feet tall. It is | 300.00 | 93230 | 0.22753925487632942 Toyon | This is a beautiful toyon tree that can grow to be over 20 feet tall. It is an e | 10.00 | 93230 | 0.23497374266229387 California Peppertree | This is a beautiful peppertree that can grow to be over 30 feet tall. It is an e | 25.00 | 93230 | 0.24215884459965364 California Redwood | This is a beautiful redwood tree that can grow to be over 300 feet tall. It is a | 1000.00 | 93230 | 0.24564130578287147 Cherry Tree | This is a beautiful cherry tree that will produce delicious cherries. It is an d | 75.00 | 93230 | 0.24846117929767153 (5 rows) Time: 28.724 ms demo=#
這項查詢執行 28 毫秒,並從 cymbal_products 資料表傳回符合要求的樹木清單,以及商店 1583 的現有商品目錄。
建構 ANN 索引
當我們只有小型資料集時,可以輕鬆使用精確搜尋掃描所有嵌入資料,但當資料量增加時,載入和回應時間也會增加。如要提升效能,您可以為嵌入資料建立索引。以下範例說明如何使用 Google ScaNN 索引處理向量資料。
如果連線中斷,請重新連線至示範資料庫:
psql "host=$INSTANCE_IP user=postgres sslmode=require dbname=demo"
啟用 alloydb_scann 擴充功能:
CREATE EXTENSION IF NOT EXISTS alloydb_scann;
建立索引:
CREATE INDEX cymbal_embedding_scann ON cymbal_embedding USING scann (embedding cosine);
嘗試執行與先前相同的查詢,並比較結果:
demo=# SELECT cp.product_name, left(cp.product_description,80) as description, cp.sale_price, cs.zip_code, (ce.embedding <=> google_ml.embedding('bge-base-1.5','What kind of fruit trees grow well here?')::vector) as distance FROM cymbal_products cp JOIN cymbal_embedding ce on ce.uniq_id=cp.uniq_id 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 5; product_name | description | sale_price | zip_code | distance -----------------------+----------------------------------------------------------------------------------+------------+----------+--------------------- California Sycamore | This is a beautiful sycamore tree that can grow to be over 100 feet tall. It is | 300.00 | 93230 | 0.22753925487632942 Toyon | This is a beautiful toyon tree that can grow to be over 20 feet tall. It is an e | 10.00 | 93230 | 0.23497374266229387 California Peppertree | This is a beautiful peppertree that can grow to be over 30 feet tall. It is an e | 25.00 | 93230 | 0.24215884459965364 California Redwood | This is a beautiful redwood tree that can grow to be over 300 feet tall. It is a | 1000.00 | 93230 | 0.24564130578287147 Fremont Cottonwood | This is a beautiful cottonwood tree that can grow to be over 100 feet tall. It i | 200.00 | 93230 | 0.2533482837690365 (5 rows) Time: 14.665 ms demo=#
查詢執行時間略為縮短,如果資料集較大,這項改善會更明顯。結果非常相似,只有櫻桃樹被弗里蒙特棉紙樹取代。
請嘗試其他查詢,並參閱說明文件,進一步瞭解如何選擇向量索引。
別忘了,AlloyDB Omni 還有更多功能和研究室。
8. 清理環境
我們現在可以使用 AlloyDB Omni 和 AI 模型刪除 GKE 叢集
刪除 GKE 叢集
在 Cloud Shell 中執行:
export PROJECT_ID=$(gcloud config get project)
export LOCATION=us-central1
export CLUSTER_NAME=alloydb-ai-gke
gcloud container clusters delete ${CLUSTER_NAME} \
--project=${PROJECT_ID} \
--region=${LOCATION}
預期的控制台輸出內容:
student@cloudshell:~$ gcloud container clusters delete ${CLUSTER_NAME} \ > --project=${PROJECT_ID} \ > --region=${LOCATION} The following clusters will be deleted. - [alloydb-ai-gke] in [us-central1] Do you want to continue (Y/n)? Y Deleting cluster alloydb-ai-gke...done. Deleted
刪除 VM
在 Cloud Shell 中執行:
export PROJECT_ID=$(gcloud config get project)
export ZONE=us-central1-a
gcloud compute instances delete instance-1 \
--project=${PROJECT_ID} \
--zone=${ZONE}
預期的控制台輸出內容:
student@cloudshell:~$ export PROJECT_ID=$(gcloud config get project) export ZONE=us-central1-a gcloud compute instances delete instance-1 \ --project=${PROJECT_ID} \ --zone=${ZONE} Your active configuration is: [cloudshell-5399] The following instances will be deleted. Any attached disks configured to be auto-deleted will be deleted unless they are attached to any other instances or the `--keep-disks` flag is given and specifies them for keeping. Deleting a disk is irreversible and any data on the disk will be lost. - [instance-1] in [us-central1-a] Do you want to continue (Y/n)? Y Deleted
如果您為這個程式碼研究室建立了新專案,可以改為刪除整個專案:https://console.cloud.google.com/cloud-resource-manager
9. 恭喜
恭喜您完成程式碼研究室!
涵蓋內容
- 如何在 Google Kubernetes 叢集中部署 AlloyDB Omni
- 如何連線至 AlloyDB Omni
- 如何將資料載入 AlloyDB Omni
- 如何將開放式嵌入模型部署至 GKE
- 如何在 AlloyDB Omni 中註冊嵌入模型
- 如何為語意搜尋產生嵌入
- 如何在 AlloyDB Omni 中使用產生的嵌入項目進行語意搜尋
- 如何在 AlloyDB 中建立及使用向量索引
如要進一步瞭解如何在 AlloyDB Omni 中使用 AI,請參閱說明文件。
10. 問卷調查
輸出: