Introdução às embeddings de vetor no Cloud SQL para PostgreSQL

1. Introdução

Neste codelab, você vai aprender a usar a integração de IA do Cloud SQL para PostgreSQL combinando a pesquisa vetorial com embeddings da Vertex AI.

30b7c4dcdd8bb68f.png

Pré-requisitos

  • Conhecimento básico do console do Google Cloud
  • Habilidades básicas na interface de linha de comando e no Cloud Shell

O que você vai aprender

  • Como implantar uma instância do Cloud SQL para PostgreSQL
  • Como criar um banco de dados e ativar a integração com a IA do Cloud SQL
  • Como carregar dados para o banco de dados
  • Como usar o modelo de embedding da Vertex AI no Cloud SQL
  • Como enriquecer o resultado usando o modelo generativo da Vertex AI
  • Como melhorar a performance usando o índice vetorial

O que é necessário

  • Uma conta e um projeto do Google Cloud
  • Um navegador da Web, como o Chrome, com suporte para o console do Google Cloud e o Cloud Shell

2. Configuração e requisitos

Configuração de ambiente autoguiada

  1. Faça login no Console do Google Cloud e crie um novo projeto ou reutilize um existente. Crie uma conta do Gmail ou do Google Workspace, se ainda não tiver uma.

fbef9caa1602edd0.png

a99b7ace416376c4.png

5e3ff691252acf41.png

  • O Nome do projeto é o nome de exibição para os participantes do projeto. É uma string de caracteres não usada pelas APIs do Google e pode ser atualizada quando você quiser.
  • O ID do projeto precisa ser exclusivo em todos os projetos do Google Cloud e não pode ser mudado após a definição. O console do Cloud gera automaticamente uma string exclusiva. Em geral, não importa o que seja. Na maioria dos codelabs, é necessário fazer referência ao ID do projeto, normalmente identificado como PROJECT_ID. Se você não gostar do ID gerado, crie outro aleatório. Se preferir, teste o seu e confira se ele está disponível. Ele não pode ser mudado após essa etapa e permanece durante o projeto.
  • Para sua informação, há um terceiro valor, um Número do projeto, que algumas APIs usam. Saiba mais sobre esses três valores na documentação.
  1. Em seguida, ative o faturamento no console do Cloud para usar os recursos/APIs do Cloud. A execução deste codelab não vai ser muito cara, se tiver algum custo. Para encerrar os recursos e evitar cobranças além deste tutorial, exclua os recursos criados ou exclua o projeto. Novos usuários do Google Cloud estão qualificados para o programa de US$ 300 de avaliação sem custos.

Inicie o Cloud Shell

Embora o Google Cloud e o Spanner possam ser operados remotamente do seu laptop, neste codelab usaremos o Google Cloud Shell, um ambiente de linha de comando executado no Cloud.

No Console do Google Cloud, clique no ícone do Cloud Shell na barra de ferramentas superior à direita:

55efc1aaa7a4d3ad.png

O provisionamento e a conexão com o ambiente levarão apenas alguns instantes para serem concluídos: Quando o processamento for concluído, você verá algo como:

7ffe5cbb04455448.png

Essa máquina virtual contém todas as ferramentas de desenvolvimento necessárias. Ela oferece um diretório principal persistente de 5 GB, além de ser executada no Google Cloud. Isso aprimora o desempenho e a autenticação da rede. Neste codelab, todo o trabalho pode ser feito com um navegador. Você não precisa instalar nada.

3. Antes de começar

Ativar API

Saída:

No Cloud Shell, verifique se o ID do projeto está configurado:

gcloud config set project [YOUR-PROJECT-ID]

Defina a variável de ambiente PROJECT_ID:

PROJECT_ID=$(gcloud config get-value project)

Ative todos os serviços necessários:

gcloud services enable sqladmin.googleapis.com \
                       compute.googleapis.com \
                       cloudresourcemanager.googleapis.com \
                       servicenetworking.googleapis.com \
                       aiplatform.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 sqladmin.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. crie uma instância do Cloud SQL

Crie uma instância do Cloud SQL com integração de banco de dados com a Vertex AI.

Criar senha do banco de dados

Defina a senha do usuário padrão do banco de dados. Você pode definir sua própria senha ou usar uma função aleatória para gerar uma:

export CLOUDSQL_PASSWORD=`openssl rand -hex 12`

Anote o valor gerado para a senha:

echo $CLOUDSQL_PASSWORD

Criar uma instância do Cloud SQL para PostgreSQL

Na sessão do Cloud Shell, execute:

gcloud sql instances create my-cloudsql-instance \
--database-version=POSTGRES_16 \
--tier=db-custom-1-3840 \
--region=us-central1 \
--edition=ENTERPRISE \
--enable-google-ml-integration \
--database-flags cloudsql.enable_google_ml_integration=on

Depois de criar a instância, precisamos definir uma senha para o usuário padrão na instância e verificar se podemos nos conectar com ela.

gcloud sql users set-password postgres \
    --instance=my-cloudsql-instance \
    --password=$CLOUDSQL_PASSWORD

Execute o comando e coloque sua senha no prompt quando estiver tudo pronto para a conexão.

gcloud sql connect my-cloudsql-instance --user=postgres

Ativar a integração com a Vertex AI

Conceda os privilégios necessários à conta de serviço interna do Cloud SQL para usar a integração da Vertex AI.

Encontre o e-mail da conta de serviço interna do Cloud SQL e exporte-o como uma variável.

SERVICE_ACCOUNT_EMAIL=$(gcloud sql instances describe my-cloudsql-instance --format="value(serviceAccountEmailAddress)")
echo $SERVICE_ACCOUNT_EMAIL

Conceda à conta de serviço do Cloud SQL acesso à Vertex AI:

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_EMAIL" \
  --role="roles/aiplatform.user"

Leia mais sobre a criação e a configuração de instâncias na documentação do Cloud SQL aqui.

5. Preparar o banco de dados

Agora precisamos criar um banco de dados e ativar o suporte a vetores.

Criar banco de dados

Crie um banco de dados com o nome quickstart_db .Para isso, temos opções diferentes, como clientes de banco de dados de linha de comando, como o psql para PostgreSQL, o SDK ou o Cloud SQL Studio. Vamos usar o SDK (gcloud) para criar bancos de dados e se conectar à instância.

No Cloud Shell, execute o comando para criar o banco de dados

gcloud sql databases create quickstart_db --instance=my-cloudsql-instance

Ativar extensões

Para trabalhar com a Vertex AI e os vetores, precisamos ativar duas extensões no banco de dados criado.

No Cloud Shell, execute o comando para se conectar ao banco de dados criado. Você vai precisar fornecer sua senha.

gcloud sql connect my-cloudsql-instance --database quickstart_db --user=postgres

Depois, após a conexão bem-sucedida, na sessão SQL, você precisa executar dois comandos:

CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE;
CREATE EXTENSION IF NOT EXISTS vector CASCADE;

Sair da sessão SQL:

exit;

6. Carregar dados

Agora precisamos criar objetos no banco de dados e carregar dados. Vamos usar dados fictícios da Cymbal Store. Os dados estão disponíveis no bucket público do Google Storage em formato CSV.

Primeiro, precisamos criar todos os objetos necessários no banco de dados. Para isso, vamos usar os comandos gcloud sql connect e gcloud storage já conhecidos para fazer o download e importar os objetos do esquema para nosso banco de dados.

No Cloud Shell, execute e forneça a senha registrada quando criamos a instância:

gcloud storage cat gs://cloud-training/gcc/gcc-tech-004/cymbal_demo_schema.sql |gcloud sql connect my-cloudsql-instance --database quickstart_db --user=postgres

O que fizemos exatamente no comando anterior? Conectamos ao nosso banco de dados e executamos o código SQL transferido por download, que criou tabelas, índices e sequências.

A próxima etapa é carregar os dados. Para isso, precisamos fazer o download dos arquivos CSV do Google Cloud Storage.

gcloud storage cp gs://cloud-training/gcc/gcc-tech-004/cymbal_products.csv .
gcloud storage cp gs://cloud-training/gcc/gcc-tech-004/cymbal_inventory.csv .
gcloud storage cp gs://cloud-training/gcc/gcc-tech-004/cymbal_stores.csv .

Em seguida, precisamos nos conectar ao banco de dados.

gcloud sql connect my-cloudsql-instance --database quickstart_db --user=postgres

E importar dados dos nossos arquivos CSV.

\copy cymbal_products from 'cymbal_products.csv' csv header
\copy cymbal_inventory from 'cymbal_inventory.csv' csv header
\copy cymbal_stores from 'cymbal_stores.csv' csv header

Sair da sessão SQL:

exit;

Se você tiver seus próprios dados e os arquivos CSV forem compatíveis com a ferramenta de importação do Cloud SQL disponível no console do Cloud, use-a em vez da abordagem de linha de comando.

7. Criar embeddings

A próxima etapa é criar embeddings para as descrições dos produtos usando o modelo textembedding-004 da Google Vertex AI e armazená-los como dados vetoriais.

Conecte-se ao banco de dados:

gcloud sql connect my-cloudsql-instance --database quickstart_db --user=postgres

E crie uma coluna virtual embutida na tabela cymbal_products usando a função de incorporação.

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

Pode levar algum tempo, mas para 900 a 1.000 linhas, não deve demorar mais do que 5 minutos e geralmente é muito mais rápido.

8. Executar pesquisa por similaridade

Agora podemos executar a pesquisa de similaridade com base nos valores de vetor calculados para as descrições e no valor de vetor recebido para nossa solicitação.

A consulta SQL pode ser executada na mesma interface de linha de comando usando gcloud sql connect ou, como alternativa, no Cloud SQL Studio. É melhor gerenciar consultas complexas e com várias linhas no Cloud SQL Studio.

Iniciar o Cloud SQL Studio

No console, clique na instância do Cloud SQL que criamos anteriormente.

b8d4844da1114a0b.png

Quando ele está aberto no painel à direita, podemos ver o Cloud SQL Studio. Clique nele.

ce3f27dc21367f2e.png

Uma caixa de diálogo será aberta para você informar o nome do banco de dados e suas credenciais:

  • Banco de dados: quickstart_db
  • Usuário: postgres
  • Senha: sua senha para o usuário principal do banco de dados

E clique no botão "AUTENTICAR".

2591c8bbc93e4e97.png

A próxima janela será aberta, e você vai clicar na guia "Editor" no lado direito para abrir o editor SQL.

74307cb101a3ba9d.png

Agora, está tudo pronto para executar nossas consultas.

Executar consulta

Execute uma consulta para receber uma lista dos produtos disponíveis mais relacionados à solicitação de um cliente. A solicitação que vamos transmitir à Vertex AI para receber o valor do vetor é "Que tipo de árvores frutíferas crescem bem aqui?"

Esta é a consulta que você pode executar para escolher os 10 primeiros itens mais adequados para nossa solicitação:

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

Copie e cole a consulta no editor do Cloud SQL Studio e pressione o botão "RUN" ou cole na sessão da linha de comando que se conecta ao banco de dados quickstart_db.

cd07549522fd04c9.png

Aqui está uma lista de produtos escolhidos que correspondem à consulta.

product_name       |                                   description                                    | sale_price | zip_code |      distance       
-------------------------+----------------------------------------------------------------------------------+------------+----------+---------------------
 Cherry Tree             | This is a beautiful cherry tree that will produce delicious cherries. It is an d |      75.00 |    93230 | 0.43922018972266397
 Meyer Lemon Tree        | Meyer Lemon trees are California's favorite lemon tree! Grow your own lemons by  |         34 |    93230 |  0.4685112926118228
 Toyon                   | This is a beautiful toyon tree that can grow to be over 20 feet tall. It is an e |      10.00 |    93230 |  0.4835677149651668
 California Lilac        | This is a beautiful lilac tree that can grow to be over 10 feet tall. It is an d |       5.00 |    93230 |  0.4947204525907498
 California Peppertree   | This is a beautiful peppertree that can grow to be over 30 feet tall. It is an e |      25.00 |    93230 |  0.5054166905547247
 California Black Walnut | This is a beautiful walnut tree that can grow to be over 80 feet tall. It is a d |     100.00 |    93230 |  0.5084219510932597
 California Sycamore     | This is a beautiful sycamore tree that can grow to be over 100 feet tall. It is  |     300.00 |    93230 |  0.5140519790508755
 Coast Live Oak          | This is a beautiful oak tree that can grow to be over 100 feet tall. It is an ev |     500.00 |    93230 |  0.5143126438081371
 Fremont Cottonwood      | This is a beautiful cottonwood tree that can grow to be over 100 feet tall. It i |     200.00 |    93230 |  0.5174774727252058
 Madrone                 | This is a beautiful madrona tree that can grow to be over 80 feet tall. It is an |      50.00 |    93230 |  0.5227400803389093
(10 rows)

9. Melhorar a resposta do LLM usando dados recuperados

Podemos melhorar a resposta do LLM da IA generativa para um aplicativo cliente usando o resultado da consulta executada e preparar uma saída significativa usando os resultados de consulta fornecidos como parte do comando para um modelo de linguagem de base generativa da Vertex AI.

Para isso, precisamos gerar um JSON com os resultados da pesquisa de vetor e usar esse JSON gerado como complemento de um comando para um modelo de LLM na Vertex AI para criar uma saída significativa. Na primeira etapa, geramos o JSON, depois o testamos no Vertex AI Studio e, na última etapa, o incorporamos a uma instrução SQL que pode ser usada em um aplicativo.

Gerar saída no formato JSON

Modifique a consulta para gerar a saída no formato JSON e retornar apenas uma linha para transmitir à Vertex AI

Cloud SQL para PostgreSQL

Confira um exemplo de consulta:

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

E aqui está o JSON esperado na saída:

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

Executar o comando no Vertex AI Studio

Podemos usar o JSON gerado para fornecê-lo como parte do comando para o modelo de texto de IA generativa no Vertex AI Studio.

Abra o chat do Vertex AI Studio no console do Cloud.

449b5959fa0e93bd.png

Talvez seja necessário ativar outras APIs, mas você pode ignorar a solicitação. Não precisamos de outras APIs para concluir o laboratório.

Esta é a instrução que vamos usar:

You are a friendly advisor helping to find a product based on the customer's needs.
Based on the client request we have loaded a list of products closely related to search.
The list in JSON format with list of values like {"product_name":"name","description":"some description","sale_price":10,"zip_code": 10234, "produt_id": "02056727942aeb714dc9a2313654e1b0"}
Here is the list of products:
[place your JSON here]
The customer asked "What tree is growing the best here?"
You should give information about the product, price and some supplemental information.
Do not ask any additional questions and assume location based on the zip code provided in the list of products.

Confira como fica quando substituímos o marcador JSON pela resposta da consulta:

You are a friendly advisor helping to find a product based on the customer's needs.
Based on the client request we have loaded a list of products closely related to search.
The list in JSON format with list of values like {"product_name":"name","description":"some description","sale_price":10,"zip_code": 10234, "produt_id": "02056727942aeb714dc9a2313654e1b0"}
Here is the list of products:
[{"product_name":"Cherry Tree","description":"This is a beautiful cherry tree that will produce delicious cherries. It is an d","sale_price":75.00,"zip_code":93230,"product_id":"d536e9e823296a2eba198e52dd23e712"}]
The customer asked "What tree is growing the best here?"
You should give information about the product, price and some supplemental information.
Do not ask any additional questions and assume location based on the zip code provided in the list of products.

Confira o resultado ao executar a solicitação com nossos valores JSON e usando o modelo gemini-2.0-flash:

2c5145ebc04daae1.png

Confira a resposta que recebemos do modelo neste exemplo. Sua resposta pode ser diferente devido a mudanças no modelo e nos parâmetros ao longo do tempo:

"Ok, com base na lista de produtos disponíveis, a melhor árvore que temos que pode crescer bem na sua área é a cerejeira.

O preço é de US $75,00.

Não tenho detalhes específicos sobre as condições de cultivo no seu CEP (93230), mas as cerejeiras geralmente prosperam em áreas com climas moderados e solo bem drenado. Elas geralmente precisam de um certo período de frio no inverno para produzir frutos, então é importante lembrar disso. No entanto, elas podem ser uma ótima adição a um jardim, oferecendo beleza e cerejas deliciosas quando as condições são adequadas."

Executar o comando em PSQL

Também é possível usar a integração da IA do Cloud SQL com a Vertex AI para receber uma resposta semelhante de um modelo generativo usando SQL diretamente no banco de dados. No entanto, para usar o modelo gemini-2.0-flash-exp, primeiro é necessário registrá-lo.

Executar no Cloud SQL para PostgreSQL

Faça upgrade da extensão para a versão 1.4.2 ou mais recente (se a versão atual for anterior). Conecte-se ao banco de dados quickstart_db usando o gcloud sql connect, como mostrado anteriormente (ou use o Cloud SQL Studio) e execute:

SELECT extversion from pg_extension where extname='google_ml_integration';

Se o valor retornado for menor que 1.4.2, execute o seguinte:

ALTER EXTENSION google_ml_integration UPDATE TO '1.4.2';

Em seguida, precisamos definir a flag do banco de dados google_ml_integration.enable_model_support como "on". Para isso, use a interface do console da Web ou execute o comando gcloud a seguir.

gcloud sql instances patch my-cloudsql-instance \
--database-flags google_ml_integration.enable_model_support=on,cloudsql.enable_google_ml_integration=on

O comando leva de 1 a 3 minutos para ser executado em segundo plano. Em seguida, verifique a nova flag na sessão do psql ou usando o Cloud SQL Studio para se conectar ao banco de dados quickstart_db.

show google_ml_integration.enable_model_support;

A saída esperada da sessão do psql é "on":

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

Em seguida, precisamos registrar dois modelos. O primeiro é o modelo text-embedding-004 já usado. Ele precisa ser registrado, já que ativamos os recursos de registro de modelo.

Para registrar a execução do modelo no psql ou no Cloud SQL Studio, use o seguinte código:

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

O próximo modelo que precisamos registrar é gemini-2.0-flash-001, que será usado para gerar a saída fácil de usar.

CALL
  google_ml.create_model(
    model_id => 'gemini-2.0-flash-001',
    model_request_url => 'https://us-central1-aiplatform.googleapis.com/v1/projects/$PROJECT_ID/locations/us-central1/publishers/google/models/gemini-2.0-flash-001:streamGenerateContent',
    model_provider => 'google',
    model_auth_type => 'cloudsql_service_agent_iam');

Você pode verificar a lista de modelos registrados selecionando informações em google_ml.model_info_view.

select model_id,model_type from google_ml.model_info_view;

Confira um exemplo de saída

quickstart_db=> select model_id,model_type from google_ml.model_info_view;
               model_id               |   model_type   
--------------------------------------+----------------
 textembedding-gecko                  | text_embedding
 textembedding-gecko@001              | text_embedding
 gemini-1.5-pro:streamGenerateContent | generic
 gemini-1.5-pro:generateContent       | generic
 gemini-1.0-pro:generateContent       | generic
 text-embedding-004                   | text_embedding
 gemini-2.0-flash-001                 | generic

Agora podemos usar o JSON gerado em uma subconsulta para fornecê-lo como parte do comando para o modelo de texto de IA generativa usando SQL.

Na sessão do psql ou do Cloud SQL Studio para o banco de dados, execute a consulta.

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

E esta é a saída esperada. A saída pode ser diferente dependendo da versão do modelo e dos parâmetros:

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

10. Criar um índice de vizinho mais próximo

Nosso conjunto de dados é muito pequeno, e o tempo de resposta depende principalmente das interações com modelos de IA. No entanto, quando você tem milhões de vetores, a pesquisa de vetores pode ocupar uma parte significativa do nosso tempo de resposta e sobrecarregar o sistema. Para melhorar isso, podemos criar um índice sobre nossos vetores.

Criar índice HNSW

Vamos tentar o tipo de índice HNSW para nosso teste. O HNSW significa Hierarchical Navigable Small World (Mundo pequeno navegável hierárquico) e representa um índice de gráfico em várias camadas.

Para criar o índice da coluna de incorporação, precisamos definir a coluna de incorporação, a função de distância e, opcionalmente, parâmetros como m ou ef_constructions. Leia sobre os parâmetros em detalhes na documentação.

CREATE INDEX cymbal_products_embeddings_hnsw ON cymbal_products
  USING hnsw (embedding vector_cosine_ops)
  WITH (m = 16, ef_construction = 64);

Saída esperada:

quickstart_db=> CREATE INDEX cymbal_products_embeddings_hnsw ON cymbal_products
  USING hnsw (embedding vector_cosine_ops)
  WITH (m = 16, ef_construction = 64);
CREATE INDEX
quickstart_db=>

Comparar resposta

Agora podemos executar a consulta de pesquisa vetorial no modo EXPLAIN e verificar se o índice foi usado.

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

Saída esperada:

 Aggregate  (cost=779.12..779.13 rows=1 width=32) (actual time=1.066..1.069 rows=1 loops=1)
   ->  Subquery Scan on trees  (cost=769.05..779.12 rows=1 width=142) (actual time=1.038..1.041 rows=1 loops=1)
         ->  Limit  (cost=769.05..779.11 rows=1 width=158) (actual time=1.022..1.024 rows=1 loops=1)
               ->  Nested Loop  (cost=769.05..9339.69 rows=852 width=158) (actual time=1.020..1.021 rows=1 loops=1)
                     ->  Nested Loop  (cost=768.77..9316.48 rows=852 width=945) (actual time=0.858..0.859 rows=1 loops=1)
                           ->  Index Scan using cymbal_products_embeddings_hnsw on cymbal_products cp  (cost=768.34..2572.47 rows=941 width=941) (actual time=0.532..0.539 rows=3 loops=1)
                                 Order By: (embedding <=> '[0.008864171,0.03693164,-0.024245683,...
<redacted>
...,0.017593635,-0.040275685,-0.03914233,-0.018452475,0.00826032,-0.07372604
]'::vector)
                           ->  Index Scan using product_inventory_pkey on cymbal_inventory ci  (cost=0.42..7.17 rows=1 width=37) (actual time=0.104..0.104 rows=0 loops=3)
                                 Index Cond: ((store_id = 1583) AND (uniq_id = (cp.uniq_id)::text))
                                 Filter: (inventory > 0)
                                 Rows Removed by Filter: 1
                     ->  Materialize  (cost=0.28..8.31 rows=1 width=8) (actual time=0.133..0.134 rows=1 loops=1)
                           ->  Index Scan using product_stores_pkey on cymbal_stores cs  (cost=0.28..8.30 rows=1 width=8) (actual time=0.129..0.129 rows=1 loops=1)
                                 Index Cond: (store_id = 1583)
 Planning Time: 112.398 ms
 Execution Time: 1.221 ms

Pela saída, podemos ver claramente que a consulta estava usando "Index Scan using cymbal_products_embeddings_hnsw".

E se executarmos a consulta sem explicar:

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

Saída esperada:

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

O resultado é o mesmo e retorna a mesma cerejeira que estava no topo da nossa pesquisa sem índice. Dependendo dos parâmetros e do tipo de índice, o resultado pode ser um pouco diferente. Durante meus testes, a consulta indexada retornou resultados em 131,301 ms, em comparação com 167,631 ms sem índice, mas estávamos lidando com um conjunto de dados muito pequeno, e a diferença seria mais significativa em um conjunto de dados maior.

Você pode testar índices diferentes disponíveis para os vetores e mais laboratórios e exemplos com a integração do Langchain disponível na documentação.

11. Limpar o ambiente

Exclua a instância do Cloud SQL

Destrua a instância do Cloud SQL quando terminar o laboratório.

No Cloud Shell, defina o projeto e as variáveis de ambiente se tiver ocorrido uma desconexão e todas as configurações anteriores forem perdidas:

export INSTANCE_NAME=my-cloudsql-instance
export PROJECT_ID=$(gcloud config get-value project)

Exclua a instância:

gcloud sql instances delete $INSTANCE_NAME --project=$PROJECT_ID

Saída esperada do console:

student@cloudshell:~$ gcloud sql instances delete $INSTANCE_NAME --project=$PROJECT_ID
All of the instance data will be lost when the instance is deleted.

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

Deleting Cloud SQL instance...done.                                                                                                                
Deleted [https://sandbox.googleapis.com/v1beta4/projects/test-project-001-402417/instances/my-cloudsql-instance].

12. Parabéns

Parabéns por concluir o codelab.

O que vimos

  • Como implantar uma instância do Cloud SQL para PostgreSQL
  • Como criar um banco de dados e ativar a integração com a IA do Cloud SQL
  • Como carregar dados para o banco de dados
  • Como usar o modelo de embedding da Vertex AI no Cloud SQL
  • Como enriquecer o resultado usando o modelo generativo da Vertex AI
  • Como melhorar a performance usando o índice vetorial

Teste um codelab semelhante para AlloyDB com o índice ScaNN em vez de HNSW.

13. Pesquisa

Saída:

Como você usará este tutorial?

Apenas leitura Leitura e exercícios