跳到主要内容
Open In Colab GitHub Repository

使用 LlamaIndex 和 Milvus 进行全文搜索

全文搜索使用精确的关键词匹配,通常利用 BM25 等算法按相关性对文档进行排名。在检索增强生成 (RAG) 系统中,此方法检索相关文本以增强 AI 生成的响应。

同时,语义搜索解释上下文含义以提供更广泛的结果。结合两种方法创建了混合搜索,可以改善信息检索——特别是在单一方法不足的情况下。

使用 Milvus 2.5 的 Sparse-BM25 方法,原始文本会自动转换为稀疏向量。这消除了手动稀疏嵌入生成的需求,并启用了平衡语义理解与关键词相关性的混合搜索策略。

在本教程中,您将学习如何使用 LlamaIndex 和 Milvus 构建使用全文搜索和混合搜索的 RAG 系统。我们将从单独实现全文搜索开始,然后通过集成语义搜索来增强它,以获得更全面的结果。

在继续本教程之前,请确保您熟悉全文搜索在 LlamaIndex 中使用 Milvus 的基础知识

先决条件

安装依赖项

在开始之前,请确保您已安装以下依赖项:

$ $pip install llama-index-vector-stores-milvus
$ $pip install llama-index-embeddings-openai
$ $pip install llama-index-llms-openai

如果您使用 Google Colab,可能需要重启运行时(导航到界面顶部的"Runtime"菜单,并从下拉菜单中选择"Restart session"。)

设置账户

本教程使用 OpenAI 进行文本嵌入和答案生成。您需要准备 OpenAI API key

import openai

openai.api_key = "sk-"

要使用 Milvus 向量存储,请指定您的 Milvus 服务器 URI(可选择使用 TOKEN)。要启动 Milvus 服务器,您可以按照 Milvus 安装指南设置 Milvus 服务器,或者简单地免费试用 Zilliz Cloud

全文搜索目前在 Milvus Standalone、Milvus Distributed 和 Zilliz Cloud 中受支持,但在 Milvus Lite 中尚未支持(计划在未来实现)。请联系 support@zilliz.com 获取更多信息。

URI = "http://localhost:19530"
# TOKEN = ""

下载示例数据

运行以下命令将示例文档下载到"data/paul_graham"目录中:

$ mkdir -p 'data/paul_graham/'
$ $wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/paul_graham/paul_graham_essay.txt' -O 'data/paul_graham/paul_graham_essay.txt'

--2025-03-27 07:49:01-- https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/paul_graham/paul_graham_essay.txt Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.108.133, 185.199.109.133, 185.199.110.133, ... Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.108.133|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 75042 (73K) [text/plain] Saving to: 'data/paul_graham/paul_graham_essay.txt'

data/paul_graham/pa 100%[===================>] 73.28K --.-KB/s in 0.07s

2025-03-27 07:49:01 (1.01 MB/s) - 'data/paul_graham/paul_graham_essay.txt' saved [75042/75042]

使用全文搜索的 RAG

将全文搜索集成到 RAG 系统中平衡了语义搜索与精确且可预测的基于关键词的检索。您也可以选择仅使用全文搜索,但建议将全文搜索与语义搜索结合使用以获得更好的搜索结果。为了演示目的,我们将展示单独的全文搜索和混合搜索。

首先,使用 SimpleDirectoryReaderLoad 加载 Paul Graham 的文章"What I Worked On":

from llama_index.core import SimpleDirectoryReader

documents = SimpleDirectoryReader("./data/paul_graham/").load_data()

# 让我们看看第一个文档
print("Example document:\n", documents[0])

Example document: Doc ID: 16b7942f-bf1a-4197-85e1-f31d51ea25a9 Text: What I Worked On February 2021 Before college the two main things I worked on, outside of school, were writing and programming. I didn't write essays. I wrote what beginning writers were supposed to write then, and probably still are: short stories. My stories were awful. They had hardly any plot, just characters with strong feelings, which I ...

使用 BM25 的全文搜索

LlamaIndex 的 MilvusVectorStore 支持全文搜索,实现高效的基于关键词的检索。通过使用内置函数作为 sparse_embedding_function,它应用 BM25 评分来对搜索结果进行排名。

在本节中,我们将演示如何使用 BM25 实现全文搜索的 RAG 系统。

from llama_index.core import VectorStoreIndex, StorageContext
from llama_index.vector_stores.milvus import MilvusVectorStore
from llama_index.vector_stores.milvus.utils import BM25BuiltInFunction
from llama_index.core import Settings

# 跳过密集嵌入模型
Settings.embed_model = None

# 构建 Milvus 向量存储创建新 Collection
vector_store = MilvusVectorStore(
uri=URI,
# token=TOKEN,
enable_dense=False,
enable_sparse=True, # 仅启用稀疏向量以演示全文搜索
sparse_embedding_function=BM25BuiltInFunction(),
overwrite=True,
)

# 在 Milvus 中存储文档
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(documents, storage_context=storage_context)

Embeddings have been explicitly disabled. Using MockEmbedding.

上述代码将示例文档插入 Milvus 并构建索引以启用全文搜索的 BM25 排名。它禁用密集嵌入并使用默认参数的 BM25BuiltInFunction

您可以在 BM25BuiltInFunction 参数中指定输入和输出 Field:

  • input_field_names (str): 输入文本 Field(默认:"text")。它指示 BM25 算法应用于哪个文本 Field。如果使用具有不同文本 Field 名称的自己的 Collection,请更改此项。
  • output_field_names (str): 存储此 BM25 函数输出的 Field(默认:"sparse_embedding")。

一旦向量存储设置完成,您可以使用查询模式"sparse"或"text_search"在 Milvus 中执行全文搜索查询:

import textwrap

query_engine = index.as_query_engine(
vector_store_query_mode="sparse", similarity_top_k=5
)
answer = query_engine.query("What did the author learn at Viaweb?")
print(textwrap.fill(str(answer), 100))

The author learned several important lessons at Viaweb. They learned about the importance of growth rate as the ultimate test of a startup, the value of building stores for users to understand retail and software usability, and the significance of being the "entry level" option in a market. Additionally, they discovered the accidental success of making Viaweb inexpensive, the challenges of hiring too many people, and the relief felt when the company was acquired by Yahoo.

自定义文本分析器

分析器在全文搜索中发挥着重要作用,将句子分解为标记并执行词汇处理,如词干提取和停用词移除。它们通常是特定于语言的。有关更多详细信息,请参阅 Milvus 分析器指南

Milvus 支持两种类型的分析器:内置分析器自定义分析器。默认情况下,BM25BuiltInFunction 使用标准内置分析器,它基于标点符号对文本进行标记化。

要使用不同的分析器或自定义现有分析器,您可以向 analyzer_params 参数传递值:

bm25_function = BM25BuiltInFunction(
analyzer_params={
"tokenizer": "standard",
"filter": [
"lowercase", # 内置过滤器
{"type": "length", "max": 40}, # 自定义单个标记的大小限制
{"type": "stop", "stop_words": ["of", "to"]}, # 自定义停用词
],
},
enable_match=True,
)

使用重新排序的混合搜索

混合搜索系统结合了语义搜索和全文搜索,优化了 RAG 系统中的检索性能。

以下示例使用 OpenAI 嵌入进行语义搜索,使用 BM25 进行全文搜索:

# 在文档上创建索引
vector_store = MilvusVectorStore(
uri=URI,
# token=TOKEN,
# enable_dense=True, # enable_dense 默认为 True
dim=1536,
enable_sparse=True,
sparse_embedding_function=BM25BuiltInFunction(),
overwrite=True,
# hybrid_ranker="RRFRanker", # hybrid_ranker 默认为 "RRFRanker"
# hybrid_ranker_params={}, # hybrid_ranker_params 默认为 {}
)

storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(
documents,
storage_context=storage_context,
embed_model="default", # "default" 将使用 OpenAI 嵌入
)

工作原理

此方法将文档存储在具有两个向量 Field 的 Milvus Collection 中:

  • embedding: 由 OpenAI 嵌入模型生成的密集嵌入,用于语义搜索。
  • sparse_embedding: 使用 BM25BuiltInFunction 计算的稀疏嵌入,用于全文搜索。

此外,我们使用了"RRFRanker"及其默认参数应用了重新排序策略。要自定义重新排序器,您可以按照 Milvus 重新排序指南配置 hybrid_rankerhybrid_ranker_params

现在,让我们使用示例查询测试 RAG 系统:

# 查询
query_engine = index.as_query_engine(
vector_store_query_mode="hybrid", similarity_top_k=5
)
answer = query_engine.query("What did the author learn at Viaweb?")
print(textwrap.fill(str(answer), 100))

The author learned several important lessons at Viaweb. These included the importance of understanding growth rate as the ultimate test of a startup, the impact of hiring too many people, the challenges of being at the mercy of investors, and the relief experienced when Yahoo bought the company. Additionally, the author learned about the significance of user feedback, the value of building stores for users, and the realization that growth rate is crucial for the long-term success of a startup.

这种混合方法通过利用语义和基于关键词的检索,确保 RAG 系统中更准确、上下文感知的响应。