Embeddings multimodaux dans AlloyDB

1. Introduction

a7e7c1d2afe05e68.png

Cet atelier de programmation explique comment déployer AlloyDB et tirer parti de l'intégration de l'IA pour la recherche sémantique à l'aide d'embeddings multimodaux. Cet atelier fait partie d'une collection d'ateliers consacrée aux fonctionnalités d'AlloyDB AI. Pour en savoir plus, consultez la page AlloyDB AI dans la documentation.

Prérequis

  • Connaissances de base concernant la console Google Cloud
  • Compétences de base concernant l'interface de ligne de commande et Cloud Shell

Points abordés

  • Déployer AlloyDB pour PostgreSQL
  • Utiliser la recherche vectorielle multimodale
  • Activer les opérateurs AlloyDB/AI
  • Utiliser différents opérateurs AlloyDB AI pour la recherche multimodale
  • Utiliser AlloyDB AI pour combiner les résultats de recherche de texte et d'images

Prérequis

  • Un compte Google Cloud et un projet Google Cloud
  • Un navigateur Web tel que Chrome compatible avec la console Google Cloud et Cloud Shell

2. Préparation

Configuration de l'environnement au rythme de chacun

  1. Connectez-vous à la console Google Cloud, puis créez un projet ou réutilisez un projet existant. Si vous n'avez pas encore de compte Gmail ou Google Workspace, vous devez en créer un.

fbef9caa1602edd0.png

a99b7ace416376c4.png

5e3ff691252acf41.png

  • Le nom du projet est le nom à afficher pour les participants au projet. Il s'agit d'une chaîne de caractères non utilisée par les API Google. Vous pourrez toujours le modifier.
  • L'ID du projet est unique parmi tous les projets Google Cloud et non modifiable une fois défini. La console Cloud génère automatiquement une chaîne unique (en général, vous n'y accordez d'importance particulière). Dans la plupart des ateliers de programmation, vous devrez indiquer l'ID de votre projet (généralement identifié par PROJECT_ID). Si l'ID généré ne vous convient pas, vous pouvez en générer un autre de manière aléatoire. Vous pouvez également en spécifier un et voir s'il est disponible. Après cette étape, l'ID n'est plus modifiable et restera donc le même pour toute la durée du projet.
  • Pour information, il existe une troisième valeur (le numéro de projet) que certaines API utilisent. Pour en savoir plus sur ces trois valeurs, consultez la documentation.
  1. Vous devez ensuite activer la facturation dans la console Cloud pour utiliser les ressources/API Cloud. L'exécution de cet atelier de programmation est très peu coûteuse, voire sans frais. Pour désactiver les ressources et éviter ainsi que des frais ne vous soient facturés après ce tutoriel, vous pouvez supprimer le projet ou les ressources que vous avez créées. Les nouveaux utilisateurs de Google Cloud peuvent participer au programme d'essai sans frais pour bénéficier d'un crédit de 300 $.

Démarrer Cloud Shell

Bien que Google Cloud puisse être utilisé à distance depuis votre ordinateur portable, nous allons nous servir de Google Cloud Shell pour cet atelier de programmation, un environnement de ligne de commande exécuté dans le cloud.

Dans la console Google Cloud, cliquez sur l'icône Cloud Shell dans la barre d'outils supérieure :

55efc1aaa7a4d3ad.png

Le provisionnement et la connexion à l'environnement prennent quelques instants seulement. Une fois l'opération terminée, le résultat devrait ressembler à ceci :

7ffe5cbb04455448.png

Cette machine virtuelle contient tous les outils de développement nécessaires. Elle comprend un répertoire d'accueil persistant de 5 Go et s'exécute sur Google Cloud, ce qui améliore nettement les performances du réseau et l'authentification. Vous pouvez effectuer toutes les tâches de cet atelier de programmation dans un navigateur. Vous n'avez rien à installer.

3. Avant de commencer

Activer l'API

Dans Cloud Shell, assurez-vous que l'ID de votre projet est configuré :

gcloud config set project [YOUR-PROJECT-ID]

Définissez la variable d'environnement PROJECT_ID :

PROJECT_ID=$(gcloud config get-value project)

Activez tous les services nécessaires :

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

Résultat attendu

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. Déployer AlloyDB

Créez un cluster AlloyDB et une instance principale. La procédure suivante explique comment créer un cluster et une instance AlloyDB à l'aide du SDK Google Cloud. Si vous préférez utiliser la console, vous pouvez consulter la documentation sur cette page.

Avant de créer un cluster AlloyDB, nous avons besoin d'une plage d'adresses IP privées disponible dans notre VPC, qui sera utilisée par la future instance AlloyDB. Si nous ne l'avons pas, nous devons le créer et l'attribuer pour qu'il soit utilisé par les services Google internes. Nous pourrons ensuite créer le cluster et l'instance.

Créer une plage d'adresses IP privées

Nous devons configurer l'accès au service privé dans notre VPC pour AlloyDB. L'hypothèse ici est que nous avons le réseau VPC "par défaut" dans le projet et qu'il sera utilisé pour toutes les actions.

Créez la plage d'adresses IP privées :

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

Créez une connexion privée à l'aide de la plage d'adresses IP allouée :

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

Résultat attendu sur la console :

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

Créer un cluster AlloyDB

Dans cette section, nous allons créer un cluster AlloyDB dans la région us-central1.

Définissez le mot de passe de l'utilisateur postgres. Vous pouvez définir votre propre mot de passe ou utiliser une fonction aléatoire pour en générer un.

export PGPASSWORD=`openssl rand -hex 12`

Résultat attendu sur la console :

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

Notez le mot de passe PostgreSQL (il vous servira plus tard).

echo $PGPASSWORD

Vous aurez besoin de ce mot de passe à l'avenir pour vous connecter à l'instance en tant qu'utilisateur postgres. Je vous suggère de le noter ou de le copier quelque part pour pouvoir l'utiliser plus tard.

Résultat attendu sur la console :

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

Créer un cluster d'essai sans frais

Si vous n'avez jamais utilisé AlloyDB, vous pouvez créer un cluster d'essai sans frais :

Définissez la région et le nom du cluster AlloyDB. Nous allons utiliser la région us-central1 et alloydb-aip-01 comme nom de cluster :

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

Exécutez la commande pour créer le cluster :

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

Résultat attendu sur la console :

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.                                                                                                                                                                                                                                                           

Créez une instance principale AlloyDB pour le cluster dans la même session Cloud Shell. Si vous êtes déconnecté, vous devrez définir à nouveau les variables d'environnement pour la région et le nom du cluster.

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

Résultat attendu sur la console :

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.                                                                                                                                                                                                                                                     

Créer un cluster AlloyDB Standard

Si ce n'est pas votre premier cluster AlloyDB dans le projet, créez un cluster standard.

Définissez la région et le nom du cluster AlloyDB. Nous allons utiliser la région us-central1 et alloydb-aip-01 comme nom de cluster :

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

Exécutez la commande pour créer le cluster :

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

Résultat attendu sur la console :

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.                                                                                                                                                                                                                                                           

Créez une instance principale AlloyDB pour le cluster dans la même session Cloud Shell. Si vous êtes déconnecté, vous devrez définir à nouveau les variables d'environnement pour la région et le nom du cluster.

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

Résultat attendu sur la console :

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. Préparer la base de données

Nous devons créer une base de données, activer l'intégration de Vertex AI, créer des objets de base de données et importer les données.

Accorder les autorisations nécessaires à AlloyDB

Ajoutez des autorisations Vertex AI à l'agent de service AlloyDB.

Ouvrez un autre onglet Cloud Shell à l'aide du signe "+" situé en haut.

4ca978f5142bb6ce.png

Dans le nouvel onglet Cloud Shell, exécutez :

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"

Résultat attendu sur la console :

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
 

Fermez l'onglet en exécutant la commande "exit" dans l'onglet :

exit

Se connecter à AlloyDB Studio

Dans les chapitres suivants, toutes les commandes SQL nécessitant une connexion à la base de données peuvent également être exécutées dans AlloyDB Studio. Pour exécuter la commande, vous devez ouvrir l'interface de la console Web de votre cluster AlloyDB en cliquant sur l'instance principale.

ef4bfbcf0ed2ef3a.png

Cliquez ensuite sur AlloyDB Studio à gauche :

5c155cbcd7d43a1.png

Choisissez la base de données postgres et l'utilisateur postgres, puis indiquez le mot de passe noté lors de la création du cluster. Cliquez ensuite sur le bouton "Authenticate" (S'authentifier).

1c9dab73c6836798.png

L'interface AlloyDB Studio s'ouvre. Pour exécuter les commandes dans la base de données, cliquez sur l'onglet "Editor 1" (Éditeur 1) à droite.

b36c28f8165119ca.png

L'interface qui s'ouvre vous permet d'exécuter des commandes SQL.

cf43aa20f292797e.png

Créer une base de données

Créez un démarrage rapide de base de données.

Dans l'éditeur AlloyDB Studio, exécutez la commande suivante.

Créez une base de données :

CREATE DATABASE quickstart_db

Résultat attendu :

Statement executed successfully

Se connecter à quickstart_db

Reconnectez-vous au studio à l'aide du bouton permettant de changer d'utilisateur ou de base de données.

e826ad973eb23a74.png

Dans la liste déroulante, sélectionnez la nouvelle base de données quickstart_db et utilisez les mêmes nom d'utilisateur et mot de passe qu'avant.

1ca70c59b5aea8c1.png

Une nouvelle connexion s'ouvre, vous permettant de travailler avec des objets de la base de données quickstart_db.

6. Exemples de données

Nous devons maintenant créer des objets dans la base de données et charger des données. Nous allons utiliser un magasin fictif "Cymbal" avec des données fictives.

Avant d'importer les données, nous devons activer les extensions compatibles avec les types de données et les index. Nous avons besoin de deux extensions : l'une compatible avec le type de données vectorielles et l'autre avec l'index AlloyDB ScaNN.

Dans AlloyDB Studio, exécutez la connexion à quickstart_db.

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

L'ensemble de données est préparé et placé sous la forme d'un fichier SQL qui peut être chargé dans la base de données à l'aide de l'interface d'importation. Dans Cloud Shell, exécutez les commandes suivantes :

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

La commande utilise le SDK AlloyDB pour créer un utilisateur nommé "agentspace_user", puis importe des exemples de données directement du bucket GCS vers la base de données, en créant tous les objets nécessaires et en insérant les données.

Une fois l'importation terminée, nous pouvons vérifier les tables dans AlloyDB Studio. Les tables se trouvent dans le schéma ecomm :

9ee57986d4cdf20f.png

Vérifiez également le nombre de lignes dans l'une des tables.

51c3c55881157da3.png

Nous avons bien importé nos données d'exemple et pouvons passer aux étapes suivantes.

7. Recherche sémantique à l'aide de représentations vectorielles continues de texte

Dans ce chapitre, nous allons essayer d'utiliser la recherche sémantique à l'aide d'embeddings textuels et la comparer à la recherche textuelle et en texte intégral Postgres traditionnelle.

Commençons par la recherche classique à l'aide du langage SQL PostgreSQL standard avec l'opérateur LIKE.

Si nous essayons de rechercher une veste de pluie à l'aide de la requête suivante :

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 requête ne renvoie aucune ligne, car elle aurait besoin de mots exacts comme "conditions humides" et "veste" dans le nom ou la description du produit. Une "veste pour temps humide" n'est pas la même chose qu'une "veste pour temps pluvieux".

Nous pouvons essayer d'inclure toutes les variantes possibles dans la recherche. Essayons d'inclure seulement deux mots. Exemple :

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;

Cela renverrait plusieurs lignes, mais toutes ne correspondraient pas parfaitement à notre demande de vestes, et il serait difficile de les trier par pertinence. Par exemple, si nous ajoutons d'autres conditions comme "pour les hommes", la complexité de la requête augmente considérablement. Nous pouvons également essayer la recherche en texte intégral, mais nous rencontrons des limites liées à la précision des mots et à la pertinence de la réponse.

Nous pouvons maintenant effectuer une recherche similaire à l'aide d'embeddings. Nous avons déjà précalculé les embeddings de nos produits à l'aide de différents modèles. Nous allons utiliser le dernier modèle Gemini-embedding-001 de Google. Nous les avons stockés dans la colonne product_embedding de la table ecomm.products. Si nous exécutons une requête pour notre condition de recherche "rain jacket for men" (imperméable pour homme) à l'aide de la requête suivante :

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;

Il renverra non seulement les vestes pour temps humide, mais aussi tous les résultats seront triés en plaçant les résultats les plus pertinents en haut.

La requête avec des embeddings renvoie des résultats en 90 à 150 ms, dont une partie du temps est consacrée à l'obtention des données à partir du modèle d'embedding cloud. Si nous examinons le plan d'exécution, la requête adressée au modèle est incluse dans le temps de planification. La partie de la requête qui effectue la recherche elle-même est assez courte. Il faut moins de 7 ms pour effectuer la recherche dans 29 000 enregistrements à l'aide de l'index ScaNN 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)

Il s'agissait d'une recherche d'embedding textuel à l'aide du modèle d'embedding textuel uniquement. Mais nous avons aussi des images pour nos produits et nous pouvons les utiliser avec la recherche. Dans le chapitre suivant, nous verrons comment le modèle multimodal utilise les images pour la recherche.

8. Utiliser la recherche multimodale

La recherche sémantique basée sur le texte est utile, mais il peut être difficile de décrire des détails complexes. La recherche multimodale d'AlloyDB offre un avantage en permettant la découverte de produits à partir d'images. Cela est particulièrement utile lorsque la représentation visuelle clarifie l'intention de recherche plus efficacement que les descriptions textuelles seules. Par exemple, "trouve-moi un manteau comme celui sur la photo".

Revenons à notre exemple de veste. Si je dispose d'une photo d'une veste similaire à celle que je recherche, je peux la transmettre au modèle d'embedding multimodal de Google et la comparer aux embeddings des images de mes produits. Dans notre tableau, nous avons déjà calculé les embeddings pour les images de nos produits dans la colonne product_image_embedding. Vous pouvez voir le modèle utilisé dans la colonne product_image_embedding_model.

Pour notre recherche, nous pouvons utiliser la fonction image_embedding afin d'obtenir l'embedding de notre image et de le comparer aux embeddings précalculés. Pour activer la fonction, nous devons nous assurer d'utiliser la bonne version de l'extension google_ml_integration.

Vérifions la version actuelle de l'extension. Dans AlloyDB Studio, exécutez :

SELECT extversion FROM pg_extension WHERE extname = 'google_ml_integration';
  

Si la version est antérieure à 1.4.4, exécutez la procédure suivante.

CALL google_ml.upgrade_to_preview_version();

Vérifiez à nouveau la version de l'extension. Il doit s'agir de la version 1.4.4.

Voici un exemple d'image pour la recherche, mais vous pouvez utiliser n'importe quelle image personnalisée. Il vous suffit de l'importer dans le stockage Google ou une autre ressource accessible au public, puis d'insérer l'URI dans la requête.

9f33ca0c73ea2b19.png

Il est importé dans gs://pr-public-demo-data/alloydb-retail-demo/user_photos/4.png.

Recherche d'images par images

Nous essayons d'abord de rechercher uniquement par image :

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;

Nous avons pu trouver des vestes chaudes dans l'inventaire.

La recherche d'images renvoie des éléments qui ressemblent à l'image fournie pour la comparaison. Comme je l'ai déjà mentionné, vous pouvez essayer d'importer vos propres images dans un bucket public et voir si l'outil peut trouver différents types de vêtements.

Nous avons utilisé le modèle "multimodalembedding@001" de Google pour notre recherche d'images. Notre fonction image_embedding envoie l'image à Vertex AI, la convertit en vecteur et la renvoie pour la comparer aux vecteurs stockés pour les images de notre base de données.

Nous pouvons également vérifier à l'aide de "EXPLAIN ANALYZE" la rapidité de fonctionnement avec notre index AlloyDB ScaNN.

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)

Comme dans l'exemple précédent, nous pouvons constater que la majeure partie du temps a été consacrée à la conversion de notre image en embeddings à l'aide du point de terminaison cloud, et que la recherche vectorielle elle-même ne prend que 2,5 ms.

Recherche d'images par texte

Avec le multimodal, nous pouvons également transmettre une description textuelle de la veste que nous essayons de rechercher au modèle à l'aide de google_ml.text_embedding pour le même modèle et la comparer aux embeddings d'images pour voir quelles images il renvoie.

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;

Nous avons obtenu un ensemble de doudounes grises ou foncées.

Nous avons obtenu un ensemble de vestes légèrement différent, mais l'IA a correctement sélectionné les vestes en fonction de notre description et en recherchant dans les embeddings d'images.

Essayons une autre façon de rechercher parmi les descriptions en utilisant notre embedding pour l'image de recherche.

Recherche de texte par images

Nous avons essayé de rechercher des images en transmettant l'embedding de notre image et en le comparant aux embeddings d'images précalculés pour nos produits. Nous avons également essayé de rechercher des images en transmettant l'embedding pour notre requête textuelle et en effectuant une recherche parmi le même embedding pour les images de produits. Essayons maintenant d'utiliser l'embedding pour notre image et de le comparer aux embeddings textuels des descriptions de produits. L'embedding est stocké dans la colonne product_description_embedding et utilise le même modèle multimodalembedding@001.

Voici notre requête :

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;

Ici, nous avons un ensemble de vestes légèrement différent, avec des couleurs grises ou foncées, dont certaines sont identiques ou très proches de celles choisies par d'autres méthodes de recherche.

Elle renvoie les mêmes vestes que ci-dessus, mais dans un ordre légèrement différent. Grâce à notre intégration pour les images, il peut comparer les intégrations calculées pour la description textuelle et renvoyer l'ensemble de produits approprié.

Vous pouvez également combiner des embeddings de texte et d'image, par exemple à l'aide de la fusion par rang réciproque. Voici un exemple de requête de ce type, dans laquelle nous avons combiné deux recherches en attribuant un score à chaque classement et en ordonnant les résultats en fonction du score combiné.

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;

Vous pouvez essayer de modifier différents paramètres dans la requête pour voir si cela peut améliorer vos résultats de recherche.

L'atelier est terminé. Pour éviter des frais inattendus, nous vous recommandons de supprimer les ressources inutilisées.

Vous pouvez également utiliser d'autres opérateurs d'IA pour classer les résultats, comme décrit dans la documentation.

9. Nettoyer l'environnement

Détruisez les instances et le cluster AlloyDB une fois l'atelier terminé.

Supprimer le cluster AlloyDB et toutes les instances

Le cluster est détruit avec l'option "force", qui supprime également toutes les instances appartenant au cluster.

Dans Cloud Shell, définissez le projet et les variables d'environnement si vous avez été déconnecté et que tous les paramètres précédents sont perdus :

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

Supprimez le cluster :

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

Résultat attendu sur la console :

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.   

Supprimer les sauvegardes AlloyDB

Supprimez toutes les sauvegardes AlloyDB du cluster :

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

Résultat attendu sur la console :

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. Félicitations

Bravo ! Vous avez terminé cet atelier de programmation. Vous avez appris à utiliser la recherche multimodale dans AlloyDB à l'aide de fonctions d'embedding pour les textes et les images. Vous pouvez essayer de tester la recherche multimodale et de l'améliorer avec la fonction google_ml.rank en utilisant l'atelier de programmation pour les opérateurs AlloyDB/AI.

Points abordés

  • Déployer AlloyDB pour PostgreSQL
  • Utiliser la recherche vectorielle multimodale
  • Activer les opérateurs AlloyDB/AI
  • Utiliser différents opérateurs AlloyDB AI pour la recherche multimodale
  • Utiliser AlloyDB AI pour combiner les résultats de recherche de texte et d'images

11. Enquête

Résultat :

Comment allez-vous utiliser ce tutoriel ?

Je vais le lire uniquement Je vais le lire et effectuer les exercices