AlloyDB Omni и локальная модель искусственного интеллекта в Kubernetes.

1. Введение

В этой лаборатории кода вы узнаете, как развернуть AlloyDB Omni на GKE и использовать его с открытой моделью внедрения, развернутой в том же кластере Kubernetes. Развертывание модели рядом с экземпляром базы данных в том же кластере GKE снижает задержку и зависимость от сторонних сервисов. Кроме того, этого могут требовать требования безопасности, когда данные не должны покидать организацию и не допускается использование сторонних сервисов.

391e4244b25a7db0.png

Предварительные условия

  • Базовое понимание Google Cloud, консоли.
  • Базовые навыки работы с интерфейсом командной строки и Cloud Shell.

Что вы узнаете

  • Как развернуть AlloyDB Omni в кластере Google Kubernetes
  • Как подключиться к AlloyDB Omni
  • Как загрузить данные в AlloyDB Omni
  • Как развернуть открытую модель внедрения в GKE
  • Как зарегистрировать модель внедрения в AlloyDB Omni
  • Как генерировать вложения для семантического поиска
  • Как использовать сгенерированные внедрения для семантического поиска в AlloyDB Omni
  • Как создавать и использовать векторные индексы в AlloyDB

Что вам понадобится

  • Учетная запись Google Cloud и проект Google Cloud
  • Веб-браузер, например Chrome, с поддержкой консоли Google Cloud и Cloud Shell.

2. Настройка и требования

Самостоятельная настройка среды

  1. Войдите в Google Cloud Console и создайте новый проект или повторно используйте существующий. Если у вас еще нет учетной записи Gmail или Google Workspace, вам необходимо ее создать .

fbef9caa1602edd0.png

a99b7ace416376c4.png

5e3ff691252acf41.png

  • Имя проекта — это отображаемое имя для участников этого проекта. Это строка символов, не используемая API Google. Вы всегда можете обновить его.
  • Идентификатор проекта уникален для всех проектов Google Cloud и является неизменяемым (невозможно изменить после его установки). Cloud Console автоматически генерирует уникальную строку; обычно тебя не волнует, что это такое. В большинстве лабораторий кода вам потребуется указать идентификатор проекта (обычно идентифицируемый как PROJECT_ID ). Если вам не нравится сгенерированный идентификатор, вы можете создать другой случайный идентификатор. Альтернативно, вы можете попробовать свой собственный и посмотреть, доступен ли он. Его нельзя изменить после этого шага и он сохраняется на протяжении всего проекта.
  • К вашему сведению, есть третье значение — номер проекта , которое используют некоторые API. Подробнее обо всех трех этих значениях читайте в документации .
  1. Затем вам необходимо включить выставление счетов в Cloud Console, чтобы использовать облачные ресурсы/API. Прохождение этой лаборатории кода не будет стоить много, если вообще что-то стоить. Чтобы отключить ресурсы и избежать выставления счетов за пределами этого руководства, вы можете удалить созданные вами ресурсы или удалить проект. Новые пользователи Google Cloud имеют право на участие в программе бесплатной пробной версии стоимостью 300 долларов США .

Запустить Cloud Shell

Хотя Google Cloud можно управлять удаленно с вашего ноутбука, в этой лаборатории вы будете использовать Google Cloud Shell , среду командной строки, работающую в облаке.

В Google Cloud Console щелкните значок Cloud Shell на верхней правой панели инструментов:

55efc1aaa7a4d3ad.png

Подготовка и подключение к среде займет всего несколько минут. Когда все будет готово, вы должны увидеть что-то вроде этого:

7ffe5cbb04455448.png

Эта виртуальная машина оснащена всеми необходимыми инструментами разработки. Он предлагает постоянный домашний каталог объемом 5 ГБ и работает в Google Cloud, что значительно повышает производительность сети и аутентификацию. Всю работу в этой лаборатории кода можно выполнять в браузере. Вам не нужно ничего устанавливать.

3. Прежде чем начать

Включить API

Выход:

В Cloud Shell убедитесь, что идентификатор вашего проекта настроен:

PROJECT_ID=$(gcloud config get-value project)
echo $PROJECT_ID

Если он не определен в конфигурации облачной оболочки, настройте его с помощью следующих команд

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. Разверните AlloyDB Omni на GKE.

Для развертывания AlloyDB Omni на GKE нам необходимо подготовить кластер Kubernetes в соответствии с требованиями, перечисленными в требованиях к оператору AlloyDB Omni .

Создать кластер GKE

Нам необходимо развернуть стандартный кластер GKE с конфигурацией пула, достаточной для развертывания модуля с экземпляром AlloyDB Omni. Нам нужно как минимум 2 процессора и 8 ГБ оперативной памяти для Omni, а также немного места для служб оператора и мониторинга.

Настройте переменные среды для вашего развертывания.

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.

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. Мы можем выполнить шаги, описанные в документации по установке диспетчера сертификатов.

Мы используем инструмент командной строки Kubernetes, kubectl, который уже установлен в Cloud Shell. Перед использованием утилиты нам необходимо получить учетные данные для нашего кластера.

gcloud container clusters get-credentials ${CLUSTER_NAME} --region=${LOCATION}

Теперь мы можем использовать kubectl для установки менеджера сертификатов:

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

Секретное значение пароля представляет собой представление Base64 слова пароля «VeryStrongPassword». Более надежный способ — использовать секретный менеджер Google для хранения значения пароля. Подробнее об этом можно прочитать в документации .

Сохраните манифест как my-omni.yaml , чтобы применить его на следующем шаге. Если вы находитесь в Cloud Shell, вы можете сделать это с помощью редактора, нажав кнопку «Открыть редактор» в правом верхнем углу терминала.

47ab85dad9afdff7.png

После сохранения файла с именем my-omni.yaml вернитесь обратно в терминал, нажав кнопку «Открыть терминал».

b9b7747b39dbe8c7.png

Примените манифест my-omni.yaml к кластеру с помощью утилиты kubectl:

kubectl apply -f my-omni.yaml

Ожидаемый вывод консоли:

secret/db-pw-my-omni created
dbcluster.alloydbomni.dbadmin.goog/my-omni created

Проверьте статус вашего кластера my-omni с помощью утилиты kubectl:

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

Когда кластер будет готов, мы сможем использовать двоичные файлы клиента PostgreSQL в модуле экземпляра AlloyDB Omni. Мы находим идентификатор модуля, а затем используем kubectl для прямого подключения к нему и запуска клиентского программного обеспечения. Пароль — 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. Развертывание модели AI на GKE

Чтобы протестировать интеграцию AlloyDB Omni AI с локальными моделями, нам необходимо развернуть модель в кластере.

Создайте пул узлов для модели

Чтобы запустить модель, нам нужно подготовить пул узлов для выполнения вывода. Лучший подход с точки зрения производительности — это пул с графическими ускорителями, использующий конфигурацию узла, например g2-standard-8 с ускорителем Nvidia L4.

Создайте пул узлов с помощью ускорителя 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

Подготовьте манифест развертывания

Для развертывания модели нам необходимо подготовить манифест развертывания.

Мы используем модель внедрения BGE Base v1.5 от Hugging Face. Карточку модели можно прочитать здесь . Для развертывания модели мы можем использовать уже подготовленные инструкции от 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, используя знак «+» вверху.

4ca978f5142bb6ce.png

И запустите команду 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 в качестве поля перехода, подключитесь к AlloyDB Omni со своей клиентской виртуальной машины и создайте базу данных.

Нам нужно поле перехода, поскольку внешний балансировщик нагрузки GKE для Omni предоставляет вам доступ из VPC с использованием частного IP-адреса, но не позволяет подключаться из-за пределов VPC. В целом это более безопасно и не предоставляет доступ к вашему экземпляру базы данных из Интернета. Пожалуйста, проверьте диаграмму для ясности.

391e4244b25a7db0.png

Чтобы создать виртуальную машину в сеансе Cloud Shell, выполните:

export ZONE=us-central1-a
gcloud compute instances create instance-1 \
    --zone=$ZONE 

Найдите IP-адрес конечной точки AlloyDB Omni с помощью kubectl в Cloud Shell:

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 — это IP-адрес, который мы будем использовать в наших примерах для подключения к экземпляру AlloyDB Omni.

Подключитесь к виртуальной машине с помощью gcloud:

gcloud compute ssh instance-1 --zone=$ZONE 

Если будет предложено создать ключ SSH, выполните инструкции. Подробнее о ssh-подключении читайте в документации .

В сеансе ssh на виртуальной машине установите клиент PostgreSQL:

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

Экспортируйте IP-адрес балансировщика нагрузки AlloyDB Omni, как показано в следующем примере (замените 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. Мы можем использовать ту же клиентскую виртуальную машину, которая использовалась для создания демонстрационной базы данных. Google Cloud SDK должен быть уже установлен там, если вы использовали настройки по умолчанию для образа виртуальной машины. Но если вы использовали собственное изображение без Google SDK, вы можете добавить его, следуя документации .

Экспортируйте IP-адрес балансировщика нагрузки AlloyDB Omni, как показано в следующем примере (замените 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"

Включите расширение alydb_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. Очистите окружающую среду

Теперь мы можем удалить наш кластер GKE с помощью AlloyDB Omni и модели AI.

Удалить кластер 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

Удалить виртуальную машину

В 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. Поздравления

Поздравляем с завершением работы над кодом.

Что мы рассмотрели

  • Как развернуть AlloyDB Omni в кластере Google Kubernetes
  • Как подключиться к AlloyDB Omni
  • Как загрузить данные в AlloyDB Omni
  • Как развернуть открытую модель внедрения в GKE
  • Как зарегистрировать модель внедрения в AlloyDB Omni
  • Как генерировать вложения для семантического поиска
  • Как использовать сгенерированные внедрения для семантического поиска в AlloyDB Omni
  • Как создавать и использовать векторные индексы в AlloyDB

Подробнее о работе с ИИ в AlloyDB Omni можно прочитать в документации .

10. Опрос

Выход:

Как вы будете использовать этот урок?

Только прочитай это Прочитайте его и выполните упражнения.