ביצוע חיפוש וקטורי של דמיון ב-Bigtable על ידי מציאת השכנים הקרובים ביותר (K-nearest neighbors)

חיפוש דמיון וקטורי יכול לעזור לכם לזהות מושגים דומים ומשמעות הקשרית בנתוני Bigtable. המשמעות היא שהוא יכול לספק תוצאות רלוונטיות יותר כשמסננים נתונים שמאוחסנים בטווח מפתחות שצוין. דוגמאות לתרחישי שימוש:

  • התאמה סמנטית של הודעות למשתמש מסוים בחיפוש בתיבת הדואר הנכנס.
  • זיהוי אנומליות בטווח של חיישנים.
  • אחזור המסמכים הרלוונטיים ביותר מתוך קבוצה של מפתחות ידועים לצורך יצירה משולבת-אחזור (RAG).
  • התאמה אישית של תוצאות החיפוש כדי לשפר את חוויית החיפוש של המשתמשים. התוצאות מאוחזרות ומדורגות על סמך ההנחיות וההעדפות הקודמות שלהם שמאוחסנות ב-Bigtable.
  • אחזור של שרשורי שיחה דומים כדי למצוא ולהציג שיחות קודמות שדומות מבחינת ההקשר לשיחה הנוכחית של המשתמש, כדי לספק חוויה מותאמת אישית יותר.
  • ביטול כפילויות של הנחיות כדי לזהות הנחיות זהות או דומות מבחינה סמנטית שנשלחו על ידי אותו משתמש, וכדי להימנע מעיבוד באמצעות AI מיותר.

לפני שקוראים את הדף הזה, חשוב להבין את המושגים הבאים:

‫Bigtable תומך בפונקציות COSINE_DISTANCE() ו-EUCLIDEAN_DISTANCE(), שפועלות על הטמעות וקטוריות ומאפשרות למצוא את ה-KNN של ההטמעה של הקלט.

אתם יכולים להשתמש בממשקי ה-API של Gemini Enterprise Agent Platform text embeddings כדי ליצור ולאחסן את נתוני Bigtable כהטבעות וקטוריות. לאחר מכן, אפשר לספק את ההטמעות הווקטוריות האלה כפרמטר קלט בשאילתה כדי למצוא את הווקטורים הקרובים ביותר במרחב N-ממדי, ולחפש פריטים דומים או קשורים מבחינה סמנטית.

שתי פונקציות המרחק מקבלות את הארגומנטים vector1 ו-vector2, שהם מסוג array<> וחייבים לכלול את אותם המאפיינים ולהיות באותו האורך. לפרטים נוספים על הפונקציות האלה, אפשר לעיין במאמרים הבאים:

בדף הזה מופיע קוד שמראה איך ליצור הטמעות, לאחסן אותן ב-Bigtable ואז לבצע חיפוש KNN.

בדוגמה שבדף הזה נעשה שימוש ב-EUCLIDEAN_DISTANCE() ובספריית הלקוח של Bigtable ל-Python. עם זאת, אפשר להשתמש גם ב-COSINE_DISTANCE() ובכל ספריית לקוח שתומכת ב-GoogleSQL ל-Bigtable, כמו ספריית הלקוח של Bigtable ל-Java.

לפני שמתחילים

לפני שמנסים את דוגמאות הקוד, צריך לבצע את הפעולות הבאות.

התפקידים הנדרשים

כדי לקבל את ההרשאות שדרושות לקריאה וכתיבה ב-Bigtable, צריך לבקש מהאדמין להקצות לכם את תפקיד ה-IAM הבא:

  • Bigtable User (roles/bigtable.user) on the Bigtable instance that you want to send requests to

מגדירים את הסביבה

  1. מורידים ומתקינים את ספריית הלקוח של Bigtable ל-Python. כדי להשתמש ב-GoogleSQL לפונקציות של Bigtable, צריך להשתמש בגרסה 2.26.0 ואילך של python-bigtable. הוראות, כולל איך להגדיר אימות, זמינות במאמר Python hello world.

  2. אם אין לכם מופע Bigtable, פועלים לפי השלבים במאמר יצירת מופע.

  3. מזהים את מזהי המשאבים. כשמריצים את הקוד, מחליפים את ה-placeholders הבאים במזהים של Google Cloud הפרויקט, מופע Bigtable והטבלה:

    • PROJECT_ID
    • INSTANCE_ID
    • TABLE_ID

יצירת טבלה לאחסון הטקסט, ההטמעות וביטוי החיפוש

יוצרים טבלה עם שתי קבוצות עמודות.

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

הטמעת טקסטים באמצעות מודל בסיסי שעבר אימון מראש מ-Agent Platform

יצירת הטקסט וההטמעות לאחסון ב-Bigtable יחד עם המפתחות המשויכים. מידע נוסף זמין במאמרים בנושא קבלת הטמעות של טקסט או קבלת הטמעות מולטימודאליות.

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

הגדרת פונקציות שמאפשרות המרה לאובייקטים של בייטים

‫Bigtable מותאם לצמדי מפתח-ערך ובדרך כלל מאחסן נתונים כאובייקטים של בייטים. מידע נוסף על תכנון מודל הנתונים ל-Bigtable זמין במאמר שיטות מומלצות לתכנון סכימה.

צריך להמיר את ההטמעות שמתקבלות מ-Agent Platform, שמאוחסנות כרשימה של מספרים ממשיים ב-Python. ממירים כל רכיב לפורמט נקודה צפה של IEEE 754 בשיטת big-endian, ואז משרשרים אותם. הפונקציה הבאה מבצעת את הפעולה הזו.

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)

כתיבת ההטמעות ב-Bigtable

ממירים את ההטמעות לאובייקטים של בייטים, יוצרים מוטציה ואז כותבים את הנתונים ל-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)

הווקטורים מאוחסנים כנתונים מקודדים בינאריים שאפשר לקרוא מ-Bigtable באמצעות פונקציית המרה מהסוג BYTES לסוג ARRAY<FLOAT32>.

זו שאילתת ה-SQL:

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

אפשר להשתמש בפונקציה COSINE_DISTANCE של GoogleSQL כדי למצוא את הדמיון בין הטמעות הטקסט לבין ביטויי החיפוש שאתם מספקים. החישוב הזה יכול לקחת זמן, ולכן כדאי להשתמש בלקוח הנתונים האסינכרוני של ספריית הלקוח של Python כדי להריץ את שאילתת ה-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()

התשובה שמוחזרת היא תיאור טקסט שנוצר ומסביר מהו Bigtable.

המאמרים הבאים