在 Bigtable 中執行相似度向量搜尋,找出 K 個最鄰近的項目
相似度向量搜尋可協助您在 Bigtable 資料中找出相似概念和情境意義,因此在篩選特定鍵範圍內儲存的資料時,可提供更相關的結果。應用實例包括:
- 在收件匣搜尋中,對特定使用者的郵件進行語意比對。
- 偵測感應器範圍內的異常狀況。
- 在已知鍵的集合中,擷取最相關的文件,以進行檢索增強生成 (RAG)。
- 個人化搜尋結果:根據 Bigtable 儲存的歷史提示和偏好設定,擷取並排序結果,提升使用者的搜尋體驗。
- 系統會擷取類似的對話串,找出並顯示與使用者目前對話情境相似的過往對話,提供更個人化的體驗。
- 系統會簡化提示,找出同一位使用者提交的相同或語意相似提示,避免 AI 重複處理。
本頁說明如何使用 Bigtable 適用的 GoogleSQL 中的餘弦距離和歐氏距離向量函式,在 Bigtable 中執行相似度向量搜尋,找出 K 個最鄰近的鄰居。閱讀本頁面之前,請務必瞭解下列概念:
- 歐氏距離:測量兩個向量之間的最短距離。
- 餘弦距離: 測量兩個向量間的角度餘弦值。
- K 最鄰近 (KNN): 一種監督式機器學習演算法,用於解決分類或迴歸問題。
Bigtable 支援 COSINE_DISTANCE()
和 EUCLIDEAN_DISTANCE()
函式,這些函式可對向量嵌入內容執行作業,讓您找出輸入嵌入內容的 KNN。
您可以使用 Vertex AI 文字嵌入 API,以向量嵌入的形式生成及儲存 Bigtable 資料。然後,您可以在查詢中提供這些向量嵌入做為輸入參數,在 N 維空間中找出最鄰近的向量,搜尋語意相似或相關的項目。
這兩個距離函式都會採用 vector1
和 vector2
引數,這些引數屬於 array<>
型別,且必須包含相同維度並具有相同長度。如要進一步瞭解這些函式,請參閱下列說明:
本頁的程式碼示範如何建立嵌入、將其儲存在 Bigtable 中,然後執行 KNN 搜尋。
本頁面的範例使用 EUCLIDEAN_DISTANCE()
和 Python 適用的 Bigtable 用戶端程式庫。不過,您也可以使用 COSINE_DISTANCE()
,以及任何支援 Bigtable GoogleSQL 的用戶端程式庫,例如
Java 適用的 Bigtable 用戶端程式庫。
事前準備
請先完成下列步驟,再試用程式碼範例。
必要的角色
如要取得讀取及寫入 Bigtable 資料所需的權限,請要求管理員授予下列 IAM 角色:
- Bigtable 執行個體上的 Bigtable 使用者 (
roles/bigtable.user
),您要將要求傳送至該執行個體
設定環境
下載並安裝 Python 專用的 Bigtable 用戶端程式庫。 如要使用 GoogleSQL 執行 Bigtable 函式,您必須使用
python-bigtable
2.26.0 以上版本。如需操作說明 (包括如何設定驗證),請參閱 Python Hello World。如果沒有 Bigtable 執行個體,請按照「建立執行個體」一文中的步驟操作。
找出資源 ID。執行程式碼時,請將下列預留位置替換為 Google Cloud 專案、Bigtable 執行個體和資料表的 ID:
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")
使用 Vertex 的預先訓練基礎模型嵌入文字
生成文字和嵌入,並連同相關聯的鍵儲存在 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 的資料模型,請參閱結構定義設計最佳做法。
您需要轉換從 Vertex 傳回的嵌入內容,這些內容在 Python 中會儲存為浮點數清單。將每個元素轉換為大端 IEEE 754 浮點格式,然後將這些元素串連在一起。以下函式可達成此目的。
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)
使用 GoogleSQL for Bigtable 執行 KNN 搜尋
向量會儲存為二進位編碼資料,可使用從 BYTES
型別到 ARRAY<FLOAT32>
的轉換函式,從 Bigtable 讀取。
SQL 查詢如下:
SELECT _key, TO_VECTOR32(data['embedding']) AS embedding
FROM table WHERE _key LIKE 'store123%';
在 Python 中,您可以使用 GoogleSQL COSINE_DISTANCE
函式,找出文字嵌入與您提供的搜尋詞組之間的相似度。由於這項運算可能需要一段時間才能處理完畢,請使用 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。