Esegui la ricerca vettoriale di somiglianza in Bigtable trovare i K vicini più vicini

La ricerca vettoriale di somiglianza può aiutarti a identificare concetti simili e significato contestuale nei dati di Bigtable, il che significa che può produrre risultati più pertinenti quando filtri i dati archiviati in un intervallo di chiavi specificato. Ecco alcuni casi d'uso di esempio:

  • Ricerca nella Posta in arrivo, in cui vuoi eseguire la corrispondenza semantica dei messaggi per un determinato utente
  • Rilevamento di anomalie all'interno di un intervallo di sensori
  • Recupero dei documenti più rilevanti all'interno di un set di chiavi note per RAG (Retrieval Augmented Generation)

Questa pagina descrive come eseguire la ricerca vettoriale di somiglianza in Bigtable utilizzando le funzioni vettoriali di distanza del coseno e distanza euclidea in GoogleSQL per Bigtable per trovare i K-Nearest Neighbor. Prima di leggere questa pagina, è importante comprendere i seguenti concetti:

Bigtable supporta le funzioni COSINE_DISTANCE() e EUCLIDEAN_DISTANCE(), che operano sugli embedding vettoriali, consentendo di trovare il KNN dell'embedding di input.

Puoi utilizzare le API di incorporamento di testo di Vertex AI per generare e memorizzare i tuoi dati Bigtable come incorporamenti vettoriali. Puoi quindi fornire questi incorporamenti vettoriali come parametro di input nella query per trovare i vettori più vicini nello spazio n-dimensionale per cercare elementi semanticamente simili o correlati.

Entrambe le funzioni di distanza accettano gli argomenti vector1 e vector2, che sono di tipo array<> e devono essere costituiti dalle stesse dimensioni e avere la stessa lunghezza. Per ulteriori dettagli su queste funzioni, consulta quanto segue:

Il codice in questa pagina mostra come creare incorporamenti, archiviarli in Bigtable ed eseguire una ricerca KNN.

L'esempio in questa pagina utilizza EUCLIDEAN_DISTANCE() e la classe Libreria client Bigtable per Python. Tuttavia, puoi anche utilizzareCOSINE_DISTANCE() e qualsiasi libreria client che supporti GoogleSQL per Bigtable, ad esempio la libreria client Bigtable per Java.

Prima di iniziare

Completa i seguenti passaggi prima di provare gli esempi di codice.

Ruoli obbligatori

Per ottenere le autorizzazioni necessarie per leggere e scrivere Bigtable, chiedi all'amministratore di concederti le seguenti autorizzazioni IAM ruolo.

Configura l'ambiente

  1. Scarica e installa la libreria client Bigtable per Python. Per utilizzare le funzioni GoogleSQL per Bigtable, devi utilizzare python-bigtable 2.26.0 o versioni successive. Istruzioni, tra cui come configurare l'autenticazione, si trovano su Python hello mondo.

  2. Se non hai un'istanza Bigtable, segui i passaggi descritti in Creare un'istanza.

  3. Identifica gli ID risorsa. Quando esegui il codice, sostituisci i seguenti segnaposto con gli ID del progetto Google Cloud, dell'istanza Bigtable e della tabella:

    • PROJECT_ID
    • INSTANCE_ID
    • TABLE_ID

Crea una tabella per archiviare il testo, gli incorporamenti e la frase di ricerca

Crea una tabella con due famiglie di colonne.

Python

from google.cloud import bigtable
from google.cloud.bigtable import column_family

client = bigtable.Client(project=PROJECT_ID, admin=True)
instance = client.instance(INSTANCE_ID)
table = instance.table(TABLE_ID)
column_families = {"docs":column_family.MaxVersionsGCRule(2), "search_phrase":column_family.MaxVersionsGCRule(2)}

if not table.exists():
  table.create(column_families=column_families)
else:
  print("Table already exists")

Incorporare i testi con un modello di base preaddestrato di Vertex

Generare il testo e gli incorporamenti da archiviare in Bigtable insieme alle chiavi associate. Per ulteriore documentazione, vedi Ricevi messaggio incorporamenti oppure Ottieni incorporamenti multimodali.

Python

from typing import List, Optional
from vertexai.language_models import TextEmbeddingInput, TextEmbeddingModel
from vertexai.generative_models import GenerativeModel

#defines which LLM that we should use to generate the text
model = GenerativeModel("gemini-1.5-pro-001")

#First, use generative AI to create a list of 10 chunks for phrases
#This can be replaced with a static list of text items or your own data

chunks = []
for i in range(10):
  response = model.generate_content(
      "Generate a paragraph between 10 and 20 words that is about about either
      Bigtable or Generative AI"
)
chunks.append(response.text)
print(response.text)
#create embeddings for the chunks of text
def embed_text(
  texts: List[str] = chunks,
  task: str = "RETRIEVAL_DOCUMENT",
  model_name: str = "text-embedding-004",
  dimensionality: Optional[int] = 128,
) -> List[List[float]]:
  """Embeds texts with a pre-trained, foundational model."""
  model = TextEmbeddingModel.from_pretrained(model_name)
  inputs = [TextEmbeddingInput(text, task) for text in texts]
  kwargs = dict(output_dimensionality=dimensionality) if dimensionality else {}
  embeddings = model.get_embeddings(inputs, **kwargs)
  return [embedding.values for embedding in embeddings]

embeddings = embed_text()
print("embeddings created for text phrases")

Definisci funzioni che ti consentano di convertire in oggetti byte

Bigtable è ottimizzato per coppie chiave-valore e in genere archivia come oggetti byte. Per saperne di più sulla progettazione del modello di dati per Bigtable, consulta Best practice per la progettazione degli schemi.

Devi convertire gli embedding restituiti da Vertex, che sono memorizzati come elenco di numeri in virgola mobile in Python. Converti ogni elemento in formato a virgola mobile IEEE 754 big-endian e poi concatenali. La seguente funzione consente di ottenere questo risultato.

Python

import struct
def floats_to_bytes(float_list):
  """
  Convert a list of floats to a bytes object, where each float is represented
  by 4 big-endian bytes.

  Parameters:
  float_list (list of float): The list of floats to be converted.

  Returns:
  bytes: The resulting bytes object with concatenated 4-byte big-endian
  representations of the floats.
  """
  byte_array = bytearray()

  for value in float_list:
      packed_value = struct.pack('>f', value)
      byte_array.extend(packed_value)

  # Convert bytearray to bytes
  return bytes(byte_array)

Scrivi gli incorporamenti in Bigtable

Converti gli incorporamenti in oggetti byte, crea una mutazione e quindi scrivi a Bigtable.

Python

from google.cloud.bigtable.data  import RowMutationEntry
from google.cloud.bigtable.data  import SetCell

mutations = []
embeddings = embed_text()
for i, embedding in enumerate(embeddings):
  print(embedding)

  #convert each embedding into a byte object
  vector = floats_to_bytes(embedding)

  #set the row key which will be used to pull the range of documents (ex. doc type or user id)
  row_key = f"doc_{i}"

  row = table.direct_row(row_key)

  #set the column for the embedding based on the byte object format of the embedding
  row.set_cell("docs","embedding",vector)
  #store the text associated with vector in the same key
  row.set_cell("docs","text",chunks[i])
  mutations.append(row)

#write the rows to Bigtable
table.mutate_rows(mutations)

I vettori vengono memorizzati come dati con codifica binaria che possono essere letti da Bigtable utilizzando una funzione di conversione dal tipo BYTES a ARRAY<FLOAT32>.

Ecco la query SQL:

SELECT _key, TO_VECTOR32(data['embedding']) AS embedding
FROM table WHERE _key LIKE 'store123%';

In Python, puoi utilizzare la funzione COSINE_DISTANCE di GoogleSQL per trovare la somiglianza tra gli incorporamenti di testo e le frasi di ricerca che gli dai. Poiché l'elaborazione di questo calcolo può richiedere tempo, utilizza dei dati asincroni della libreria client cliente per eseguire la query SQL.

Python

from google.cloud.bigtable.data import BigtableDataClientAsync

#first embed the search phrase
search_embedding = embed_text(texts=["Apache HBase"])

query = """
      select _key, docs['text'] as description
      FROM knn_intro
      ORDER BY COSINE_DISTANCE(TO_VECTOR32(docs['embedding']), {search_embedding})
      LIMIT 1;
      """

async def execute_query():
  async with BigtableDataClientAsync(project=PROJECT_ID) as client:
    local_query = query
    async for row in await client.execute_query(query.format(search_embedding=search_embedding[0]), INSTANCE_ID):
      return(row["_key"],row["description"])

await execute_query()

La risposta restituita è una descrizione testuale generata descrive Bigtable.

Passaggi successivi