Incorporaciones multimodales en AlloyDB

1. Introducción

a7e7c1d2afe05e68.png

En este codelab, se proporciona una guía para implementar AlloyDB y aprovechar la integración de IA para la búsqueda semántica con embeddings multimodales. Este lab forma parte de una colección de labs dedicados a las funciones de AlloyDB AI. Puedes obtener más información en la página de AlloyDB AI en la documentación.

Requisitos previos

  • Conocimientos básicos sobre Google Cloud y la consola
  • Habilidades básicas de la interfaz de línea de comandos y de Cloud Shell

Qué aprenderás

  • Cómo implementar AlloyDB para PostgreSQL
  • Cómo usar la búsqueda de vectores multimodal
  • Cómo habilitar los operadores de AlloyDB AI
  • Cómo usar diferentes operadores de AlloyDB AI para la búsqueda multimodal
  • Cómo usar AlloyDB AI para combinar resultados de búsqueda de texto y de imágenes

Requisitos

  • Una cuenta de Google Cloud y un proyecto de Google Cloud
  • Un navegador web, como Chrome, que admita la consola de Google Cloud y Cloud Shell

2. Configuración y requisitos

Configuración del entorno de autoaprendizaje

  1. Accede a Google Cloud Console y crea un proyecto nuevo o reutiliza uno existente. Si aún no tienes una cuenta de Gmail o de Google Workspace, debes crear una.

fbef9caa1602edd0.png

a99b7ace416376c4.png

5e3ff691252acf41.png

  • El Nombre del proyecto es el nombre visible de los participantes de este proyecto. Es una cadena de caracteres que no se utiliza en las APIs de Google. Puedes actualizarla cuando quieras.
  • El ID del proyecto es único en todos los proyectos de Google Cloud y es inmutable (no se puede cambiar después de configurarlo). La consola de Cloud genera automáticamente una cadena única. Por lo general, no importa cuál sea. En la mayoría de los codelabs, deberás hacer referencia al ID de tu proyecto (suele identificarse como PROJECT_ID). Si no te gusta el ID que se generó, podrías generar otro aleatorio. También puedes probar uno propio y ver si está disponible. No se puede cambiar después de este paso y se usa el mismo durante todo el proyecto.
  • Recuerda que hay un tercer valor, un número de proyecto, que usan algunas APIs. Obtén más información sobre estos tres valores en la documentación.
  1. A continuación, deberás habilitar la facturación en la consola de Cloud para usar las APIs o los recursos de Cloud. Ejecutar este codelab no costará mucho, tal vez nada. Para cerrar recursos y evitar que se generen cobros más allá de este instructivo, puedes borrar los recursos que creaste o borrar el proyecto. Los usuarios nuevos de Google Cloud son aptos para participar en el programa Prueba gratuita de $300.

Inicia Cloud Shell

Si bien Google Cloud y Spanner se pueden operar de manera remota desde tu laptop, en este codelab usarás Google Cloud Shell, un entorno de línea de comandos que se ejecuta en la nube.

En Google Cloud Console, haz clic en el ícono de Cloud Shell en la barra de herramientas en la parte superior derecha:

55efc1aaa7a4d3ad.png

El aprovisionamiento y la conexión al entorno deberían tomar solo unos minutos. Cuando termine el proceso, debería ver algo como lo siguiente:

7ffe5cbb04455448.png

Esta máquina virtual está cargada con todas las herramientas de desarrollo que necesitarás. Ofrece un directorio principal persistente de 5 GB y se ejecuta en Google Cloud, lo que permite mejorar considerablemente el rendimiento de la red y la autenticación. Todo tu trabajo en este codelab se puede hacer en un navegador. No es necesario que instales nada.

3. Antes de comenzar

Habilitar API

En Cloud Shell, asegúrate de que tu ID del proyecto esté configurado:

gcloud config set project [YOUR-PROJECT-ID]

Configura la variable de entorno PROJECT_ID:

PROJECT_ID=$(gcloud config get-value project)

Habilita todos los servicios necesarios con el siguiente comando:

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

Resultado esperado

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.

4. Implementa AlloyDB

Crea un clúster y una instancia principal de AlloyDB. En el siguiente procedimiento, se describe cómo crear un clúster y una instancia de AlloyDB con el SDK de Google Cloud. Si prefieres el enfoque de la consola, puedes seguir la documentación aquí.

Antes de crear un clúster de AlloyDB, necesitamos un rango de IP privada disponible en nuestra VPC para que lo utilice la instancia futura de AlloyDB. Si no lo tenemos, debemos crearlo, asignarlo para que lo usen los servicios internos de Google y, luego, podremos crear el clúster y la instancia.

Crea un rango de IP privada

Debemos establecer la configuración del acceso privado a servicios en nuestra VPC para AlloyDB. Aquí, suponemos que tenemos la red de VPC “predeterminada” en el proyecto y que se utilizará para todas las acciones.

Crea el rango de IP privada:

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

Crea una conexión privada con el rango de IP asignado:

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

Resultado esperado en la consola:

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)$

Crea un clúster de AlloyDB

En esta sección, crearemos un clúster de AlloyDB en la región us-central1.

Define la contraseña para el usuario de postgres. Puedes definir tu propia contraseña o usar una función aleatoria para generar una.

export PGPASSWORD=`openssl rand -hex 12`

Resultado esperado en la consola:

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

Toma nota de la contraseña de PostgreSQL para utilizarla más adelante.

echo $PGPASSWORD

Necesitarás esa contraseña en el futuro para conectarte a la instancia como usuario de postgres. Te sugiero que la anotes o la copies en algún lugar para poder usarla más adelante.

Resultado esperado en la consola:

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

Crea un clúster de prueba gratuita

Si no usaste AlloyDB antes, puedes crear un clúster de prueba gratuito:

Define la región y el nombre del clúster de AlloyDB. Usaremos la región us-central1 y alloydb-aip-01 como nombre del clúster:

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

Ejecuta el comando para crear el clúster:

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

Resultado esperado en la consola:

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

Crea una instancia principal de AlloyDB para nuestro clúster en la misma sesión de Cloud Shell. Si te desconectas, deberás volver a definir las variables de entorno de la región y el nombre del clúster.

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

Resultado esperado en la consola:

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

Crea un clúster estándar de AlloyDB

Si no es tu primer clúster de AlloyDB en el proyecto, continúa con la creación de un clúster estándar.

Define la región y el nombre del clúster de AlloyDB. Usaremos la región us-central1 y alloydb-aip-01 como nombre del clúster:

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

Ejecuta el comando para crear el clúster:

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

Resultado esperado en la consola:

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.                                                                                                                                                                                                                                                           

Crea una instancia principal de AlloyDB para nuestro clúster en la misma sesión de Cloud Shell. Si te desconectas, deberás volver a definir las variables de entorno de la región y el nombre del clúster.

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

Resultado esperado en la consola:

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. Prepara la base de datos

Debemos crear una base de datos, habilitar la integración de Vertex AI, crear objetos de base de datos y, luego, importar los datos.

Otorga los permisos necesarios a AlloyDB

Agrega permisos de Vertex AI al agente de servicio de AlloyDB.

Abre otra pestaña de Cloud Shell con el signo "+" en la parte superior.

4ca978f5142bb6ce.png

En la nueva pestaña de Cloud Shell, ejecuta lo siguiente:

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"

Resultado esperado en la consola:

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
 

Cierra la pestaña con el comando de ejecución “exit” en la pestaña:

exit

Conéctate a AlloyDB Studio

En los siguientes capítulos, todos los comandos de SQL que requieren conexión a la base de datos se pueden ejecutar de forma alternativa en AlloyDB Studio. Para ejecutar el comando, haz clic en la instancia principal para abrir la interfaz de la consola web de tu clúster de AlloyDB.

ef4bfbcf0ed2ef3a.png

Luego, haz clic en AlloyDB Studio a la izquierda:

5c155cbcd7d43a1.png

Elige la base de datos postgres, el usuario postgres y proporciona la contraseña que anotaste cuando creamos el clúster. Luego, haz clic en el botón "Autenticar".

1c9dab73c6836798.png

Se abrirá la interfaz de AlloyDB Studio. Para ejecutar los comandos en la base de datos, haz clic en la pestaña "Editor 1" que se encuentra a la derecha.

b36c28f8165119ca.png

Se abre una interfaz en la que puedes ejecutar comandos de SQL.

cf43aa20f292797e.png

Crea la base de datos

Guía de inicio rápido para crear una base de datos

En el editor de AlloyDB Studio, ejecuta el siguiente comando.

Crea la base de datos:

CREATE DATABASE quickstart_db

Resultado esperado:

Statement executed successfully

Conéctate a quickstart_db

Vuelve a conectarte al estudio con el botón para cambiar de usuario o base de datos.

e826ad973eb23a74.png

En la lista desplegable, selecciona la nueva base de datos quickstart_db y usa el mismo usuario y contraseña que antes.

1ca70c59b5aea8c1.png

Se abrirá una nueva conexión en la que podrás trabajar con objetos de la base de datos quickstart_db.

6. Datos de muestra

Ahora debemos crear objetos en la base de datos y cargar datos. Usaremos una tienda ficticia llamada "Cymbal" con datos ficticios.

Antes de importar los datos, debemos habilitar las extensiones que admiten tipos de datos e índices. Necesitamos dos extensiones: una que admita el tipo de datos vector y otra que admita el índice de ScaNN de AlloyDB.

En AlloyDB Studio, ejecuta la conexión a quickstart_db.

CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS alloydb_scann;

El conjunto de datos se prepara y se coloca como un archivo SQL que se puede cargar en la base de datos a través de la interfaz de importación. En Cloud Shell, ejecuta los siguientes comandos:

export REGION=us-central1
export ADBCLUSTER=alloydb-aip-01
gcloud alloydb clusters import $ADBCLUSTER --region=$REGION --database=quickstart_db --gcs-uri='gs://sample-data-and-media/ecomm-retail/ecom_generic_vectors.sql' --user=postgres --sql

El comando usa el SDK de AlloyDB y crea un usuario con el nombre agentspace_user. Luego, importa datos de muestra directamente desde el bucket de GCS a la base de datos, creando todos los objetos necesarios e insertando datos.

Después de la importación, podemos verificar las tablas en AlloyDB Studio. Las tablas se encuentran en el esquema de comercio electrónico:

9ee57986d4cdf20f.png

Verifica la cantidad de filas en una de las tablas.

51c3c55881157da3.png

Importamos correctamente nuestros datos de muestra y podemos continuar con los próximos pasos.

7. Búsqueda semántica con incorporaciones de texto

En este capítulo, intentaremos usar la búsqueda semántica con embeddings de texto y la compararemos con la búsqueda de texto y de texto completo tradicional de Postgres.

Primero, probemos la búsqueda clásica con SQL de PostgreSQL estándar y el operador LIKE.

Si intentamos buscar un impermeable con la siguiente búsqueda:

SET session.my_search_var='%wet%conditions%jacket%';
SELECT
  name,
  product_description,
  retail_price,   replace(product_image_uri,'gs://','https://storage.googleapis.com/') AS public_url
FROM
  ecomm.products
WHERE
  name ILIKE current_setting('session.my_search_var')
  OR product_description ILIKE current_setting('session.my_search_var')
LIMIT
  10;

La búsqueda no devuelve ninguna fila, ya que necesitaría palabras exactas como condiciones húmedas y chaqueta para estar en el nombre o la descripción del producto. Y la "chaqueta para condiciones de humedad" no es lo mismo que la "chaqueta para condiciones de lluvia".

Podemos intentar incluir todas las variaciones posibles en la búsqueda. Intentemos incluir solo dos palabras. Por ejemplo:

SELECT
  name,
  product_description,
  retail_price,
   replace(product_image_uri,'gs://','https://storage.googleapis.com/') AS public_url
FROM
  ecomm.products
WHERE
  name ILIKE '%wet%jacket%'
  OR name ILIKE '%jacket%wet%'
  OR name ILIKE '%jacket%'
  OR name ILIKE '%%wet%'
  OR product_description ILIKE '%wet%jacket%'
  OR product_description ILIKE '%jacket%wet%'
  OR product_description ILIKE '%jacket%'
  OR product_description ILIKE '%wet%'
LIMIT
  10;

Esto devolvería varias filas, pero no todas coinciden perfectamente con nuestra solicitud de chaquetas, y es difícil ordenarlas por relevancia. Por ejemplo, si agregamos más condiciones, como "para hombres" y otras, la complejidad de la búsqueda aumentaría significativamente. También podemos probar la búsqueda de texto completo, pero incluso allí nos encontramos con limitaciones relacionadas con palabras más o menos exactas y la relevancia de la respuesta.

Ahora podemos realizar una búsqueda similar con incorporaciones. Ya calculamos previamente los embeddings de nuestros productos con diferentes modelos. Usaremos el modelo más reciente de Google, gemini-embedding-001. Los almacenamos en la columna "product_embedding" de la tabla ecomm.products. Si ejecutamos una búsqueda para nuestra condición de búsqueda "chaqueta para lluvia para hombres" con la siguiente consulta:

SELECT
  name,
  product_description,
  retail_price,
   replace(product_image_uri,'gs://','https://storage.googleapis.com/') AS public_url,
  product_embedding <=> embedding ('gemini-embedding-001','wet conditions jacket for men')::vector AS distance
FROM
  ecomm.products
ORDER BY distance
LIMIT
  10;

Devolverá no solo las chaquetas para condiciones húmedas, sino que también ordenará todos los resultados para colocar los más relevantes en la parte superior.

La búsqueda con incorporaciones devuelve resultados en un plazo de 90 a 150 ms, en el que se dedica una parte del tiempo a obtener los datos del modelo de incorporación en la nube. Si observamos el plan de ejecución, la solicitud al modelo se incluye en el tiempo de planificación. La parte de la consulta que realiza la búsqueda en sí es bastante corta. Se tarda menos de 7 ms en realizar la búsqueda en 29,000 registros con el índice de ScaNN de AlloyDB.

Limit  (cost=2709.20..2718.82 rows=10 width=490) (actual time=6.966..7.049 rows=10 loops=1)
   ->  Index Scan using embedding_scann on products  (cost=2709.20..30736.40 rows=29120 width=490) (actual time=6.964..7.046 rows=10 loops=1)
         Order By: (product_embedding <=> '[-0.0020264734,-0.016582033,0.027258193
...
-0.0051468653,-0.012440448]'::vector)
         Limit: 10
 Planning Time: 136.579 ms
 Execution Time: 6.791 ms
(6 rows)

Esa fue la búsqueda de incorporaciones de texto con el modelo de incorporación solo de texto. Pero también tenemos imágenes de nuestros productos que podemos usar con la búsqueda. En el siguiente capítulo, mostraremos cómo el modelo multimodal usa imágenes para la búsqueda.

8. Cómo usar la Búsqueda multimodal

Si bien la búsqueda semántica basada en texto es útil, describir detalles complejos puede ser un desafío. La búsqueda multimodal de AlloyDB ofrece una ventaja, ya que permite el descubrimiento de productos a través de la entrada de imágenes. Esto es especialmente útil cuando la representación visual aclara la intención de búsqueda de manera más eficaz que las descripciones textuales por sí solas. Por ejemplo, "Encuéntrame un abrigo como este de la foto".

Volvamos a nuestro ejemplo de la chaqueta. Si tengo una foto de una chaqueta similar a lo que quiero encontrar, puedo pasarla al modelo de incorporación multimodal de Google y compararla con las incorporaciones de las imágenes de mis productos. En nuestra tabla, ya calculamos las incorporaciones de las imágenes de nuestros productos en la columna product_image_embedding, y puedes ver el modelo que se usó en la columna product_image_embedding_model.

Para nuestra búsqueda, podemos usar la función image_embedding para obtener la incorporación de nuestra imagen y compararla con las incorporaciones precalculadas. Para habilitar la función, debemos asegurarnos de que estamos usando la versión correcta de la extensión google_ml_integration.

Verifiquemos la versión actual de la extensión. En la ejecución de AlloyDB Studio

SELECT extversion FROM pg_extension WHERE extname = 'google_ml_integration';
  

Si la versión es anterior a la 1.4.4, ejecuta el siguiente procedimiento.

CALL google_ml.upgrade_to_preview_version();

Luego, vuelve a verificar la versión de la extensión. Debería ser 1.4.4.

Esta es mi imagen de muestra para la búsqueda, pero puedes usar cualquier imagen personalizada. Solo debes subirlo al almacenamiento de Google o a otro recurso disponible públicamente y colocar el URI en la consulta.

9f33ca0c73ea2b19.png

y se sube a gs://pr-public-demo-data/alloydb-retail-demo/user_photos/4.png

Búsqueda de imágenes por imágenes

Primero, intentamos buscar solo por la imagen:

SELECT
  name,
  product_description,
  retail_price,
  replace(product_image_uri,'gs://','https://storage.googleapis.com/') AS public_url,
  product_image_embedding <=> google_ml.image_embedding (model_id => 'multimodalembedding@001',image => 'gs://pr-public-demo-data/alloydb-retail-demo/user_photos/4.png', mimetype => 'image/png')::vector AS distance
FROM
  ecomm.products
ORDER BY distance
LIMIT
  4;

Y pudimos encontrar algunas chaquetas abrigadas en el inventario.

La búsqueda de imágenes nos devuelve elementos que se parecen a la imagen que proporcionamos para la comparación. Como ya mencioné, puedes intentar subir tus propias imágenes a un bucket público y ver si puede encontrar diferentes tipos de ropa.

Usamos el modelo "multimodalembedding@001" de Google para nuestra búsqueda de imágenes. Nuestra función image_embedding envía la imagen a Vertex AI, la convierte en un vector y la devuelve para compararla con los vectores almacenados de las imágenes en nuestra base de datos.

También podemos verificar con "EXPLAIN ANALYZE" qué tan rápido funciona con nuestro índice de ScaNN de AlloyDB.

Limit  (cost=971.70..975.55 rows=4 width=490) (actual time=2.453..2.477 rows=4 loops=1)
   ->  Index Scan using product_image_embedding_scann on products  (cost=971.70..28998.90 rows=29120 width=490) (actual time=2.451..2.475 rows=4 loops=1)
         Order By: (product_image_embedding <=> '[0.02119865,0.034206174,0.030682731,
...
,-0.010307034,-0.010053742]'::vector)
         Limit: 4
 Planning Time: 913.322 ms
 Execution Time: 2.517 ms
(6 rows)

Y, de nuevo, como en el ejemplo anterior, podemos ver que la mayor parte del tiempo se dedicó a convertir nuestra imagen en embeddings con el extremo de Cloud y la búsqueda vectorial en sí solo lleva 2.5 ms.

Búsqueda de imágenes por texto

Con la función multimodal, también podemos pasar una descripción de texto de la chaqueta que intentamos buscar al modelo usando google_ml.text_embedding para el mismo modelo y compararla con las incorporaciones de imágenes para ver qué imágenes devuelve.

SELECT
  name,
  product_description,
  retail_price,
  replace(product_image_uri,'gs://','https://storage.googleapis.com/') AS public_url,
  product_image_embedding <=> google_ml.text_embedding (model_id => 'multimodalembedding@001',content => 'puffy jacket for men, grey or dark colour')::vector AS distance
FROM
  ecomm.products
ORDER BY distance
LIMIT
  4;

Y obtuvimos un conjunto de chaquetas acolchadas con colores grises u oscuros.

Obtuvimos un conjunto de chaquetas ligeramente diferente, pero seleccionó correctamente las chaquetas según nuestra descripción y la búsqueda en las incorporaciones de imágenes.

Probemos otra forma de buscar entre las descripciones usando nuestra incorporación para la imagen de búsqueda.

Búsqueda de texto en imágenes

Intentamos buscar imágenes pasando el embedding de nuestra imagen y comparándolo con los embeddings de imágenes precalculados de nuestros productos. También intentamos buscar imágenes pasando la incorporación para nuestra solicitud de texto y buscar entre la misma incorporación las imágenes de los productos. Ahora intentemos usar la incorporación para nuestra imagen y compararla con las incorporaciones de texto para las descripciones de los productos. La incorporación se almacena en la columna product_description_embedding y usa el mismo modelo multimodalembedding@001.

Esta es nuestra búsqueda:

SELECT
  name,
  product_description,
  retail_price,
  replace(product_image_uri,'gs://','https://storage.googleapis.com/') AS public_url,
  product_description_embedding <=> google_ml.image_embedding (model_id => 'multimodalembedding@001',image => 'gs://pr-public-demo-data/alloydb-retail-demo/user_photos/4.png', mimetype => 'image/png')::vector AS distance

FROM
  ecomm.products
ORDER BY distance
LIMIT
  4;

Aquí obtuvimos un conjunto de chaquetas ligeramente diferente con colores grises u oscuros, en el que algunas son iguales o muy similares a las elegidas con otra forma de búsqueda.

Y devuelve las mismas chaquetas que antes, pero en un orden ligeramente diferente. Según nuestra incorporación para imágenes, puede compararse con las incorporaciones calculadas para la descripción de texto y devolver el conjunto correcto de productos.

También puedes experimentar combinando embeddings de texto y de imágenes, por ejemplo, con la fusión de rango recíproco. Este es un ejemplo de una consulta de este tipo en la que combinamos dos búsquedas, asignamos una puntuación a cada clasificación y ordenamos los resultados según la puntuación combinada.

WITH image_search AS (
            SELECT id,
                RANK () OVER (ORDER BY  product_image_embedding <=>google_ml.image_embedding(model_id => 'multimodalembedding@001',image => 'gs://pr-public-demo-data/alloydb-retail-demo/user_photos/4.png', mimetype => 'image/png')::vector) AS rank
                FROM ecomm.products
                ORDER BY product_image_embedding <=>google_ml.image_embedding(model_id => 'multimodalembedding@001',image => 'gs://pr-public-demo-data/alloydb-retail-demo/user_photos/4.png', mimetype => 'image/png')::vector LIMIT 5
        ),
      text_search AS (
            SELECT id,
                RANK () OVER (ORDER BY product_description_embedding <=>google_ml.text_embedding(model_id => 'multimodalembedding@001',content => 'puffy jacket for men, grey or dark colour'
    )::vector) AS rank
            FROM ecomm.products
            ORDER BY product_description_embedding <=>google_ml.text_embedding(model_id => 'multimodalembedding@001',content => 'puffy jacket for men, grey or dark colour'
    )::vector LIMIT 5
        ),
      rrf_score AS (
        SELECT
            COALESCE(image_search.id, text_search.id) AS id,
            COALESCE(1.0 / (60 + image_search.rank), 0.0) + COALESCE(1.0 / (60 + text_search.rank), 0.0) AS rrf_score
        FROM image_search FULL OUTER JOIN text_search ON image_search.id = text_search.id
        ORDER BY rrf_score DESC
      )
      SELECT 
        ep.name,
        ep.product_description,
        ep.retail_price,
        replace(ep.product_image_uri,'gs://','https://storage.googleapis.com/') AS public_url
      FROM ecomm.products ep, rrf_score 
      WHERE 
        ep.id=rrf_score.id 
      ORDER by rrf_score DESC
      LIMIT 4;

Puedes intentar jugar con diferentes parámetros en la búsqueda y ver si se pueden mejorar los resultados.

Con esto, se completará el lab. Para evitar cargos inesperados, se recomienda borrar los recursos que no se usen.

Además, puedes usar otros operadores de IA para clasificar los resultados, como se describe en la documentación.

9. Limpia el entorno

Cuando termines el lab, destruye las instancias y el clúster de AlloyDB

Borra el clúster de AlloyDB y todas las instancias

El clúster se destruye con la opción force que también borra todas las instancias que pertenecen al clúster.

En Cloud Shell, define el proyecto y las variables de entorno si te desconectaste y se perdieron todos los parámetros de configuración anteriores:

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

Borra el clúster:

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

Resultado esperado en la consola:

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.   

Borra las copias de seguridad de AlloyDB

Borra todas las copias de seguridad de AlloyDB del clúster:

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

Resultado esperado en la consola:

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.                                                                                                                                                                                                                                                            

10. Felicitaciones

Felicitaciones por completar el codelab. Aprendiste a usar la búsqueda multimodal en AlloyDB con funciones de incorporación para textos e imágenes. Puedes intentar probar la búsqueda multimodal y mejorarla con la función google_ml.rank usando el codelab para los operadores de AlloyDB AI.

Temas abordados

  • Cómo implementar AlloyDB para PostgreSQL
  • Cómo usar la búsqueda de vectores multimodal
  • Cómo habilitar los operadores de AlloyDB AI
  • Cómo usar diferentes operadores de AlloyDB AI para la búsqueda multimodal
  • Cómo usar AlloyDB AI para combinar resultados de búsqueda de texto y de imágenes

11. Encuesta

Resultado:

¿Cómo usarás este instructivo?

Solo lo leeré Lo leeré y completaré los ejercicios