🚀 免費嘗試 Zilliz Cloud,完全托管的 Milvus,體驗速度提升 10 倍!立即嘗試

milvus-logo
LFAI
  • Home
  • Blog
  • 使用 Milvus 2.5 開始混合語意/全文本搜尋

使用 Milvus 2.5 開始混合語意/全文本搜尋

  • Engineering
December 17, 2024
Stefan Webb

在這篇文章中,我們將教您如何快速使用新的全文檢索功能,並將其與傳統的以向量嵌入為基礎的語意檢索結合。

需求

首先,確保您已經安裝 Milvus 2.5:

pip install -U pymilvus[model]

並使用Milvus 文檔中的安裝指示,擁有一個運行中的 Milvus Standalone (例如:在您的本機上)。

建立資料模式和搜尋索引

我們匯入所需的類別和函式:

from pymilvus import MilvusClient, DataType, Function, FunctionType, model

您可能已經注意到 Milvus 2.5 的兩個新項目,FunctionFunctionType ,我們稍後會解釋。

接下來,我們使用 Milvus Standalone 開啟資料庫,也就是在本機建立資料模式。請注意,Milvus Lite 目前不支援全文檢索,只支援 Milvus Standalone 和 Milvus Distributed。

client = MilvusClient(uri="http://localhost:19530")

schema = client.create_schema()

schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True, auto_id=True)
schema.add_field(field_name="text", datatype=DataType.VARCHAR, max_length=1000, enable_analyzer=True)
schema.add_field(field_name="dense", datatype=DataType.FLOAT_VECTOR, dim=768),
schema.add_field(field_name="sparse", datatype=DataType.SPARSE_FLOAT_VECTOR)
{'auto_id': False, 'description': '', 'fields': [{'name': 'id', 'description': '', 'type': <DataType.INT64: 5>, 'is_primary': True, 'auto_id': True}, {'name': 'text', 'description': '', 'type': <DataType.VARCHAR: 21>, 'params': {'max_length': 1000, 'enable_analyzer': True}}, {'name': 'dense', 'description': '', 'type': <DataType.FLOAT_VECTOR: 101>, 'params': {'dim': 768}}, {'name': 'sparse', 'description': '', 'type': <DataType.SPARSE_FLOAT_VECTOR: 104>}], 'enable_dynamic_field': False}

您可能已經注意到enable_analyzer=True 參數。這會告訴 Milvus 2.5 在這個欄位上啟用詞彙分析器,並建立一個詞彙和詞彙頻率的列表,這是全文檢索所需要的。sparse 欄位將保存文件的向量表示,作為從解析text 產生的字元袋。

但我們如何連接textsparse 欄位,並告訴 Milvussparse 應如何從text 計算出來?這就是我們需要調用Function 物件並將其加入模式的地方:

bm25_function = Function(
    name="text_bm25_emb", # Function name
    input_field_names=["text"], # Name of the VARCHAR field containing raw text data
    output_field_names=["sparse"], # Name of the SPARSE_FLOAT_VECTOR field reserved to store generated embeddings
    function_type=FunctionType.BM25,
)

schema.add_function(bm25_function)
{'auto_id': False, 'description': '', 'fields': [{'name': 'id', 'description': '', 'type': <DataType.INT64: 5>, 'is_primary': True, 'auto_id': True}, {'name': 'text', 'description': '', 'type': <DataType.VARCHAR: 21>, 'params': {'max_length': 1000, 'enable_analyzer': True}}, {'name': 'dense', 'description': '', 'type': <DataType.FLOAT_VECTOR: 101>, 'params': {'dim': 768}}, {'name': 'sparse', 'description': '', 'type': <DataType.SPARSE_FLOAT_VECTOR: 104>, 'is_function_output': True}], 'enable_dynamic_field': False, 'functions': [{'name': 'text_bm25_emb', 'description': '', 'type': <FunctionType.BM25: 1>, 'input_field_names': ['text'], 'output_field_names': ['sparse'], 'params': {}}]}

Function 物件的抽象比應用全文檢索的抽象更廣泛。將來,它可能會用於一個欄位需要成為另一個欄位的函數的其他情況。在我們的案例中,我們透過函式FunctionType.BM25 來指定sparsetext 的函式。BM25 是指資訊檢索中常用的度量,用於計算查詢與文件的相似度(相對於文件集合)。

我們使用 Milvus 的預設嵌入模型,即paraphrase-albert-small-v2

embedding_fn = model.DefaultEmbeddingFunction()

下一步是加入我們的搜尋索引。我們有一個用於密集向量,另一個用於稀疏向量。索引類型是SPARSE_INVERTED_INDEXBM25 ,因為全文搜尋所需的搜尋方法與標準密集向量的不同。

index_params = client.prepare_index_params()

index_params.add_index(
    field_name="dense",
    index_type="AUTOINDEX", 
    metric_type="COSINE"
)

index_params.add_index(
    field_name="sparse",
    index_type="SPARSE_INVERTED_INDEX", 
    metric_type="BM25"
)

最後,我們建立集合:

client.drop_collection('demo')
client.list_collections()
[]
client.create_collection(
    collection_name='demo', 
    schema=schema, 
    index_params=index_params
)

client.list_collections()
['demo']

如此一來,我們就有了一個空的資料庫,可以接受文字文件並執行語意和全文檢索!

插入資料與 Milvus 以前的版本沒有什麼不同:

docs = [
    'information retrieval is a field of study.',
    'information retrieval focuses on finding relevant information in large datasets.',
    'data mining and information retrieval overlap in research.'
]

embeddings = embedding_fn(docs)

client.insert('demo', [
    {'text': doc, 'dense': vec} for doc, vec in zip(docs, embeddings)
])
{'insert_count': 3, 'ids': [454387371651630485, 454387371651630486, 454387371651630487], 'cost': 0}

在進行混合搜尋之前,讓我們先說明一次全文搜尋:

search_params = {
    'params': {'drop_ratio_search': 0.2},
}

results = client.search(
    collection_name='demo', 
    data=['whats the focus of information retrieval?'],
    output_fields=['text'],
    anns_field='sparse',
    limit=3,
    search_params=search_params
)

搜索參數drop_ratio_search 指的是在搜索算法過程中要丟掉得分較低的文件的比例。

讓我們來查看結果:

for hit in results[0]:
    print(hit)
{'id': 454387371651630485, 'distance': 1.3352930545806885, 'entity': {'text': 'information retrieval is a field of study.'}}
{'id': 454387371651630486, 'distance': 0.29726022481918335, 'entity': {'text': 'information retrieval focuses on finding relevant information in large datasets.'}}
{'id': 454387371651630487, 'distance': 0.2715056240558624, 'entity': {'text': 'data mining and information retrieval overlap in research.'}}

現在讓我們結合我們所學到的知識來執行混合搜尋,將獨立的語意搜尋和全文搜尋結合起來,再加上一個reeranker:

from pymilvus import AnnSearchRequest, RRFRanker
query = 'whats the focus of information retrieval?'
query_dense_vector = embedding_fn([query])

search_param_1 = {
    "data": query_dense_vector,
    "anns_field": "dense",
    "param": {
        "metric_type": "COSINE",
    },
    "limit": 3
}
request_1 = AnnSearchRequest(**search_param_1)

search_param_2 = {
    "data": [query],
    "anns_field": "sparse",
    "param": {
        "metric_type": "BM25",
        "params": {"drop_ratio_build": 0.0}
    },
    "limit": 3
}
request_2 = AnnSearchRequest(**search_param_2)

reqs = [request_1, request_2]
ranker = RRFRanker()

res = client.hybrid_search(
    collection_name="demo",
    output_fields=['text'],
    reqs=reqs,
    ranker=ranker,
    limit=3
)
for hit in res[0]:
    print(hit)
{'id': 454387371651630485, 'distance': 0.032786883413791656, 'entity': {'text': 'information retrieval is a field of study.'}}
{'id': 454387371651630486, 'distance': 0.032258063554763794, 'entity': {'text': 'information retrieval focuses on finding relevant information in large datasets.'}}
{'id': 454387371651630487, 'distance': 0.0317460335791111, 'entity': {'text': 'data mining and information retrieval overlap in research.'}}

您可能已經注意到了,這與具有兩個獨立語意欄位的混合搜尋(自 Milvus 2.4 起可用)沒有什麼不同。在這個簡單的範例中,結果與全文檢索相同,但對於較大的資料庫和特定關鍵字檢索,混合檢索的召回率通常較高。

總結

您現在已經具備了使用 Milvus 2.5 執行全文和混合語意/全文搜尋所需的所有知識。請參閱下列文章,以瞭解更多關於全文搜尋如何運作,以及為什麼它是語意搜尋的補充:

Try Managed Milvus for Free

Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.

Get Started

Like the article? Spread the word

繼續閱讀