混合搜尋結合標準關鍵字型文字搜尋與語意向量搜尋,可提升搜尋關聯性。關鍵字搜尋會找出完全相符的結果,向量搜尋則會找出語意與查詢內容相似的結果,即使沒有共用關鍵字也沒關係。混合搜尋結合了這些方法,可擷取字彙和語意相關的結果,提供的結果比單一搜尋方法更全面準確。
AlloyDB for PostgreSQL 可讓您執行混合搜尋,結合向量和文字搜尋。舉例來說,您可以建立全文搜尋索引,例如 GIN、RUM 或 BM25 索引,用於全文搜尋。您可以建立 ScaNN 等向量索引或 HNSW,進行向量相似度搜尋。接著,AlloyDB 可以使用倒數排名融合 (RRF) 等演算法,合併並重新排序這兩種搜尋類型的結果,將多個搜尋結果清單合併為一個依相關性排序的清單。
如要進行高效率或高相關性的文字搜尋,可以建立及管理 RUM 索引,或建立及管理 BM25 索引。
您也可以將 AlloyDB 向量搜尋結果與下列支援的外部搜尋引擎的權杖搜尋結果合併:
您可以使用多種方式在 AlloyDB 中執行混合型搜尋。請參閱下表,根據您的用途選擇最合適的方法:
| 做法 | 說明 | 用途 |
|---|---|---|
| SQL 函式 | hybrid_search() 是內建函式,可使用 RRF 結合向量和文字搜尋結果,簡化混合型搜尋。 |
如果您需要以便利的方式直接在 SQL 中執行混合搜尋,建議採用這個做法。 |
| 原始 SQL 查詢 | 手動建構 SQL 查詢,分別執行向量和文字搜尋,並使用 RRF 合併結果。 | 如果您需要完全控管查詢邏輯,或需要實作超出 hybrid_search() 函式功能的自訂排序。 |
| LangChain 整合 | 在 LangChain 中使用 AlloyDBVectorStore 類別執行混合型搜尋。 |
如果您使用 LangChain 架構建構 Python 應用程式,並想將 AlloyDB 整合為向量儲存空間,提供混合搜尋功能。 |
事前準備
- 啟用
google_ml_integration擴充功能。 啟用預先發布版 AI 函式:
SET google_ml_integration.enable_preview_ai_functions = true;如果您打算對儲存在外部資料庫中的資料執行混合式搜尋,請務必先設定連線:
使用文字和向量輸入內容執行相似度搜尋
如要在 AlloyDB 中執行混合搜尋,請在資料表上建立向量索引和文字搜尋索引。然後合併兩次搜尋的結果,並重新排序,呈現最相關的資訊。
建立 GIN 索引
廣義反向索引 (GIN) 索引是一種專門的索引類型,可針對複合值 (例如陣列、JSONB 和全文搜尋資料) 進行最佳化搜尋。
如要在文字資料上建立 GIN 索引來執行全文搜尋,請執行下列指令:
CREATE INDEX INDEX_NAME ON TABLE USING GIN (to_tsvector('english', COLUMN_NAME));
更改下列內容:
INDEX_NAME:要建立的索引名稱,例如my_gin_index。TABLE:要新增索引的資料表。COLUMN_NAME:儲存要搜尋文字資料的資料欄。
建立 ScaNN 索引
如要使用 ScaNN 演算法,將兩層樹狀結構索引套用至含有儲存向量嵌入的資料欄,請執行下列 DDL 查詢:
CREATE INDEX INDEX_NAME ON TABLE
USING scann (EMBEDDING_COLUMN DISTANCE_FUNCTION)
WITH (num_leaves=NUM_LEAVES_VALUE);
更改下列內容:
INDEX_NAME:要建立的索引名稱,例如my_scann_index。索引名稱會在資料庫中共用。請確保資料庫中每個資料表都有專屬的索引名稱。TABLE:要新增索引的資料表。EMBEDDING_COLUMN:儲存vector資料的資料欄。DISTANCE_FUNCTION:要搭配這個索引使用的距離函式。選擇下列其中一個選項:L2 距離:
l2點積:
dot_product餘弦距離:
cosine
NUM_LEAVES_VALUE:要套用至這個索引的分區數量。請設為 1 到 1048576 之間的任何值。如要進一步瞭解如何決定這個值,請參閱「調整ScaNN索引」。
如要進一步瞭解不同的 ScaNN 索引設定,請參閱「選擇 」。
使用 hybrid_search 函式執行混合型搜尋
ai.hybrid_search() 函式可讓您合併多種搜尋類型 (例如向量搜尋和全文搜尋) 的結果。這項函式會使用 RRF 演算法,將各搜尋元件的排名結果合併為單一統合清單。相較於單一搜尋類型,這種做法可提供更相關的結果。
hybrid_search() 函式會動態建構及執行單一 SQL 查詢。系統會為您定義的每個搜尋元件建立一般資料表運算式 (CTE)。接著,函式會合併所有 CTE 的結果,並計算每份文件的最終 RRF 分數,產生統一的排名清單。
準備資料並建立索引
使用 hybrid_search 函式前,請先準備資料並建立必要索引。
建立資料表來儲存文件。
CREATE TABLE documents ( doc_id TEXT PRIMARY KEY, content TEXT, text_tsv tsvector GENERATED ALWAYS AS (to_tsvector('english', content)) STORED, text_embedding vector(3072) GENERATED ALWAYS AS (embedding('gemini-embedding-001', content)) STORED );插入資料。
INSERT INTO documents (doc_id, content) VALUES ('doc1', 'AlloyDB is a fully managed, PostgreSQL-compatible database service.'), ('doc2', 'It offers enterprise-grade performance, availability, and security.'), ('doc3', 'You can use it for demanding transactional and analytical workloads.'), ('doc4', 'AlloyDB integrates with Google Cloud services like Gemini Enterprise Agent Platform.'), ('doc5', 'The database supports vector embeddings for semantic search.'), ('doc6', 'alloydb_scann is an AlloyDB specific extension that provides scann index for vector search.'), ('doc7', 'alloydb_scann extension depends upon pgvector extension '), ('doc8', 'With alloydb_scann extension'), ('doc9', 'customers can create scann index'), ('doc10', 'to speed up their vector search workloads');建立索引來提升搜尋效能。如要使用向量搜尋功能,請建立
scann索引。如要進行全文搜尋,請建立GIN索引。CREATE EXTENSION IF NOT EXISTS alloydb_scann; CREATE INDEX documents_text_embedding_idx ON documents USING scann (text_embedding cosine) WITH(num_leaves = 10, quantizer = 'SQ8'); CREATE INDEX documents_text_tsv_idx ON documents USING GIN (text_tsv);
呼叫 hybrid_search 函式並查看輸出範例
如要瞭解 hybrid_search 函式接受的參數,協助您控管搜尋和融合程序,請參閱「混合搜尋函式參數」。
呼叫
hybrid_search函式,合併向量和全文搜尋結果。這個步驟會合併執行使用者搜尋輸入內容所定義查詢後得到的搜尋結果。SELECT * FROM ai.hybrid_search( search_inputs => ARRAY[ '{ "data_type": "vector", "weight": 0.5, "table_name": "documents", "key_column": "doc_id", "vec_column": "text_embedding", "distance_operator": "public.<=>", "limit": 5, "query_vector": "ai.embedding(''gemini-embedding-001'', ''managed database'')::vector" }'::JSONB, '{ "data_type": "text", "weight": 0.5, "table_name": "documents", "key_column": "doc_id", "text_column": "text_tsv", "limit": 5, "ranking_function": "ts_rank", "query_text_input": "database" }'::JSONB ], include_json_output => false );include_json_output是選用參數。詳情請參閱混合搜尋函式參數。查看輸出內容。
如果
include_json_output為false,輸出內容會包含文件 ID 和最終分數。id | score ------+---------------------- doc1 | 0.016393442622 doc5 | 0.016129032258 doc3 | 0.007936512936 doc2 | 0.007812504999 doc4 | 0.007692312692 (5 rows)如果
include_json_output為true,輸出內容會包含detail_json資料欄,其中列出各項指標的分數計算明細。id | score | detail_json ------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- doc1 | 0.01639344262 | {"item_id": "doc1", "calculation": {"component_1": {"rank": 1, "weight": 0.5, "data_type": "vector", "component_score": 0.01639344262295081967, "execute_time_ms": 5}, "component_2": {"rank": 1, "weight": 0.5, "data_type": "text", "component_score": 0.01639344262295081967, "execute_time_ms": 4}}, "final_score": 0.01639344262295082} doc5 | 0.016129032258 | {"item_id": "doc5", "calculation": {"component_1": {"rank": 2, "weight": 0.5, "data_type": "vector", "component_score": 0.01612903225806451613, "execute_time_ms": 5}, "component_2": {"rank": 2, "weight": 0.5, "data_type": "text", "component_score": 0.01612903225806451613, "execute_time_ms": 4}}, "final_score": 0.016129032258064516} ...
指定最終回傳型別的資料型別
id_type 參數可讓您指定最終回傳型別的資料型別。AlloyDB AI 會自動執行轉換。
舉例來說,如果 doc_id 欄是 TEXT,且您想將其轉換為 INTEGER,請將 NULL::INTEGER 傳遞至 id_type 參數。
CREATE TABLE product_logs (
log_id_str TEXT PRIMARY KEY,
content TEXT,
content_tsv tsvector GENERATED ALWAYS AS (to_tsvector('english', content)) STORED
);
INSERT INTO product_logs (log_id_str, content)
VALUES ('999', 'system start and services initialized');
CREATE INDEX idx_product_logs_rum ON product_logs USING rum (content_tsv rum_tsvector_ops);
SELECT
id,
pg_typeof(id)
FROM ai.hybrid_search(
ARRAY['{
"data_type": "text",
"table_name": "product_logs",
"key_column": "log_id_str",
"text_column": "content_tsv",
"query_text_input": "system",
"limit": 1
}'::jsonb],
id_type => NULL::INTEGER
);
輸出結果會顯示 id 資料欄已轉換為 INTEGER:
id | pg_typeof
------+-----------
999 | integer
(1 rows)
以下範例說明指定退貨 ID 欄資料類型的重要性,並顯示發生不符情況時會出現什麼問題。
DROP TABLE IF EXISTS product_logs;
CREATE TABLE product_logs (
log_id_str TEXT PRIMARY KEY,
content TEXT,
content_tsv tsvector GENERATED ALWAYS AS (to_tsvector('english', content)) STORED
);
INSERT INTO product_logs VALUES ('999', 'system start');
SELECT
id,
pg_typeof(id),
score
FROM ai.hybrid_search(
ARRAY['{
"data_type": "text",
"table_name": "product_logs",
"key_column": "log_id_str",
"text_column": "content_tsv",
"query_text_input": "system",
"limit": 1
}'::jsonb],
id_type => NULL::INTEGER --- CAST to INT
);
選擇文字搜尋查詢剖析器
執行全文搜尋時,AlloyDB 會提供 g_to_tsquery()
函式,協助您擷取高度相關的資訊。g_to_tsquery() (預設值) 可將純文字或標準 tsquery 格式轉換為資料更豐富的 tsquery 輸出內容,進而提升資訊檢索效果。
如果您偏好使用 PostgreSQL 剖析器函式,可以明確指定下列函式:
使用原始 SQL 執行混合搜尋
混合型搜尋會分別執行向量和文字搜尋,然後使用倒數排名融合 (RRF) 合併結果並重新排名。RRF 是一種以排名為依據的演算法,可將多份搜尋結果排名清單合併為一份排名清單,方法是為每份文件指派分數。這項分數是根據 RRF 在所有貢獻清單中的倒數排名計算,排名較高的文件貢獻度較高。
以下範例說明如何結合全文搜尋和混合搜尋,並重新排序結果。
WITH vector_search AS (
SELECT id,
RANK () OVER (ORDER BY embedding <=> ai.embedding('MODEL_ID', 'TEXT')) AS rank
FROM TABLE
ORDER BY embedding <=> ai.embedding('MODEL_ID', 'TEXT') LIMIT 10
),
text_search AS (
SELECT id,
RANK () OVER (ORDER BY ts_rank(to_tsvector('english', COLUMN_NAME), to_tsquery(KEYWORD)) desc)
FROM TABLE
WHERE to_tsvector('english', COLUMN_NAME) @@ to_tsquery(KEYWORD)
ORDER BY ts_rank(to_tsvector('english', COLUMN_NAME), to_tsquery(KEYWORD)) desc
LIMIT 10
)
SELECT
COALESCE(vector_search.id, text_search.id) AS id,
COALESCE(1.0 / (60 + vector_search.rank), 0.0) + COALESCE(1.0 / (60 + text_search.rank), 0.0) AS rrf_score
FROM vector_search FULL OUTER JOIN text_search ON vector_search.id = text_search.id
ORDER BY rrf_score DESC
LIMIT 5;
更改下列內容:
MODEL_ID:要查詢的模型 ID。如果使用 Model Garden,請指定
gemini-embedding-001做為模型 ID。這些是 AlloyDB 可用於文字嵌入的雲端模型。詳情請參閱「文字嵌入」。TABLE:包含資料的資料表。TEXT:要翻譯成向量嵌入的文字。KEYWORD:要搜尋的關鍵字。COLUMN_NAME:儲存要搜尋的文字資料的資料欄。
混合型搜尋查詢和相關一般資料表運算式 (CTE) 的說明:
vector_searchCTE:執行標準向量相似度搜尋,依餘弦距離排序結果並指派排名。並擷取語意最相似的前 10 項產品。text_searchCTE:使用to_tsvector和to_tsquery執行文字搜尋,使用ts_rank計算關聯性,並擷取前 10 個最相關的文字比對結果。Final SELECT StatementCTE:使用FULL OUTER JOIN聯結向量和文字搜尋結果,選取產品 ID,計算 RRF 分數,依分數排序,並擷取前 5 個結果。
使用原始 SQL 搭配 BM25 索引執行混合型搜尋
如果您使用 pg_textsearch 擴充功能,可以運用 BM25 索引,在混合相似度搜尋查詢中取得高精確度的評分。
如要優先取得最相關的相符項目,請依遞增 (ASC) 順序排序文字搜尋 CTE。BM25 運算子 (<@>) 會傳回負分,也就是結果越相關,分數就越負。
以下範例說明如何執行混合型向量相似度搜尋,並結合 BM25 搜尋:
WITH vector_search AS (
SELECT id,
RANK () OVER (ORDER BY embedding <=> ai.embedding('MODEL_ID', 'TEXT')) AS rank
FROM TABLE
ORDER BY embedding <=> ai.embedding('MODEL_ID', 'TEXT') LIMIT 10
),
text_search AS (
SELECT id,
RANK () OVER (ORDER BY COLUMN_NAME <@> 'KEYWORD' ASC) AS rank
FROM TABLE
ORDER BY COLUMN_NAME <@> 'KEYWORD' ASC
LIMIT 10
)
SELECT
COALESCE(vector_search.id, text_search.id) AS id,
COALESCE(1.0 / (60 + vector_search.rank), 0.0) + COALESCE(1.0 / (60 + text_search.rank), 0.0) AS rrf_score
FROM vector_search FULL OUTER JOIN text_search ON vector_search.id = text_search.id
ORDER BY rrf_score DESC
LIMIT 5;
更改下列內容:
MODEL_ID:要查詢的模型 ID。如果您使用 Vertex AI Model Garden,請指定
gemini-embedding-001做為模型 ID。這些是 AlloyDB 可用於文字嵌入的雲端模型。詳情請參閱「文字嵌入」。TABLE:包含資料的資料表。TEXT:要翻譯成向量嵌入的文字。KEYWORD:要搜尋的關鍵字。COLUMN_NAME:包含要搜尋的文字資料的欄。
例如:
WITH vector_search AS (
SELECT doc_id,
RANK () OVER (ORDER BY text_embedding <=> ai.embedding('gemini-embedding-001', 'database')) AS rank
FROM documents
ORDER BY text_embedding <=> ai.embedding('gemini-embedding-001', 'database') LIMIT 10
),
text_search AS (
SELECT doc_id,
RANK () OVER (ORDER BY content <@> 'database' ASC) AS rank
FROM documents
ORDER BY content <@> 'database' ASC
LIMIT 10
)
SELECT
COALESCE(vector_search.doc_id, text_search.doc_id) AS doc_id,
COALESCE(1.0 / (60 + vector_search.rank), 0.0) + COALESCE(1.0 / (60 + text_search.rank), 0.0) AS rrf_score
FROM vector_search FULL OUTER JOIN text_search ON vector_search.doc_id = text_search.doc_id
ORDER BY rrf_score DESC
LIMIT 5;
BM25 混合型搜尋查詢說明:
vector_searchCTE:執行標準向量相似度搜尋,使用gemini-embedding-001模型對文字查詢'database'排序結果 (依餘弦距離<=>),並指派排名。並擷取語意最相似的前 10 份文件。text_searchCTE:使用 BM25<@>運算子對content欄執行文字搜尋,計算'database'的 BM25 相關性分數,以遞增 (ASC) 順序排序,優先擷取高度相關的文件,並擷取前 10 個相符項目。Final SELECT Statement:使用FULL OUTER JOIN合併向量搜尋和文字搜尋結果,計算每個文件 ID 的倒數排名融合 (RRF) 分數,依 RRF 分數降序排序合併結果,並擷取前 5 個文件。
使用 LangChain 執行混合型搜尋
AlloyDB 向量儲存空間的混合搜尋功能結合了兩種不同的查詢策略:密集嵌入向量搜尋和關鍵字搜尋,可提高搜尋準確度。AlloyDBVectorStore 是 LangChain 向量儲存庫類別,可做為 LangChain VectorStore 類別的特定實作項目,藉此使用 LangChain。瞭解如何使用 AlloyDBVectorStore 類別,透過 AlloyDB 儲存向量嵌入。
設定 AlloyDBVectorStore 時,您可以使用 HybridSearchConfig 類別啟用及設定這項混合搜尋功能。
AlloyDB 向量存放區的混合搜尋功能會同時執行語意搜尋,瞭解查詢的意義和脈絡,並執行關鍵字搜尋,找出完全相符的詞彙。然後合併這兩項搜尋的結果,提供更全面的結果集。
後續步驟
- 瞭解如何建立及管理 BM25 索引。
- 瞭解混合型搜尋函式參數。
- 觀看混合式搜尋和 AI 函式示範。