Skip to content
LlamaIndex 文档版本 跟随上游 源快照 4384c49c 更新于 2026-10-18

混合搜索利用语义检索和关键词匹配两者的优势,提供更准确、更具上下文相关性的结果。通过结合语义搜索和关键词匹配的优点,混合搜索在复杂的信息检索任务中尤其有效。

本 notebook 演示如何在 LlamaIndex RAG 流水线中使用 Milvus 进行混合搜索。我们将从推荐的默认混合搜索(语义 + BM25)开始,然后探索其他替代的稀疏嵌入方法以及混合重排序器的自定义。

前置条件

安装依赖项

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

! 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 密钥。

import openai

openai.api_key = "sk-"

要使用 Milvus 向量存储,请指定你的 Milvus 服务器 URI(并可选择提供 TOKEN)。要启动 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/examples/data/paul_graham/paul_graham_essay.txt' -O 'data/paul_graham/paul_graham_essay.txt'

然后使用 SimpleDirectoryReaderLoad 加载 Paul Graham 的文章 “What I Worked On”:

from llama_index.core import SimpleDirectoryReader

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

# Let's take a look at the first document
print("Example document:\n", documents[0])
Example document:
 Doc ID: f9cece8c-9022-46d8-9d0e-f29d70e1dbbe
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 的混合搜索

本节展示如何使用 BM25 执行混合搜索。首先,我们将初始化 MilvusVectorStore 并为示例文档创建索引。默认配置使用:

  • 来自默认嵌入模型(OpenAI 的 text-embedding-ada-002)的稠密嵌入
  • 如果 enable_sparse 为 True,则使用 BM25 进行全文搜索
  • 如果启用混合搜索,则使用 k=60 的 RRFRanker 合并结果
# Create an index over the documnts
from llama_index.vector_stores.milvus import MilvusVectorStore
from llama_index.core import StorageContext, VectorStoreIndex

vector_store = MilvusVectorStore(
    uri=URI,
    # token=TOKEN,
    dim=1536,  # vector dimension depends on the embedding model
    enable_sparse=True,  # enable the default full-text search using BM25
    overwrite=True,  # drop the collection if it already exists
)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(
    documents, storage_context=storage_context
)
2025-04-17 03:38:16,645 [DEBUG][_create_connection]: Created new connection using: cf0f4df74b18418bb89ec512063c1244 (async_milvus_client.py:547)
Sparse embedding function is not provided, using default.
Default sparse embedding function: BM25BuiltInFunction(input_field_names='text', output_field_names='sparse_embedding').

以下是有关在 MilvusVectorStore 中配置稠密和稀疏字段的参数的更多信息:

稠密字段

  • enable_dense (bool):用于启用或禁用稠密嵌入的布尔标志。默认为 True。
  • dim (int, optional):集合中嵌入向量的维度。
  • embedding_field (str, optional):集合稠密嵌入字段的名称,默认为 DEFAULT_EMBEDDING_KEY。
  • index_config (dict, optional):用于构建稠密嵌入索引的配置。默认为 None。
  • search_config (dict, optional):用于搜索 Milvus 稠密索引的配置。请注意,它必须与 index_config 指定的索引类型兼容。默认为 None。
  • similarity_metric (str, optional):用于稠密嵌入的相似度度量,目前支持 IP、COSINE 和 L2。

稀疏字段

  • enable_sparse (bool):用于启用或禁用稀疏嵌入的布尔标志。默认为 False。
  • sparse_embedding_field (str):稀疏嵌入字段的名称,默认为 DEFAULT_SPARSE_EMBEDDING_KEY。
  • sparse_embedding_function (Union[BaseSparseEmbeddingFunction, BaseMilvusBuiltInFunction], optional):如果 enable_sparse 为 True,则应提供此对象以将文本转换为稀疏嵌入。如果为 None,则将使用默认稀疏嵌入函数(BM25BuiltInFunction),或者在现有集合没有内置函数时使用 BGEM3SparseEmbedding。
  • sparse_index_config (dict, optional):用于构建稀疏嵌入索引的配置。默认为 None。

要在查询阶段启用混合搜索,请将 vector_store_query_mode 设置为 “hybrid”。这将合并并重新排序来自语义搜索和全文搜索的结果。让我们用一个示例查询进行测试:“What did the author learn at Viaweb?”:

import textwrap

query_engine = index.as_query_engine(
    vector_store_query_mode="hybrid", similarity_top_k=5
)
response = query_engine.query("What did the author learn at Viaweb?")
print(textwrap.fill(str(response), 100))
The author learned about retail, the importance of user feedback, and the significance of growth
rate as the ultimate test of a startup at Viaweb.

自定义文本分析器

分析器在全文本搜索中起着至关重要的作用,它将句子分解为 token 并执行词法处理,例如词干提取和停用词移除。它们通常与特定语言相关。更多详细信息请参见 Milvus 分析器指南。

Milvus 支持两种类型的分析器:内置分析器和自定义分析器。默认情况下,如果 enable_sparse 设置为 True,MilvusVectorStore 将使用默认配置的 BM25BuiltInFunction,采用基于标点符号对文本进行分词的标准内置分析器。

要使用其他分析器或自定义现有分析器,你可以在构建 BM25BuiltInFunction 时向 analyzer_params 参数提供值。然后,将此函数设置为 MilvusVectorStore 中的 sparse_embedding_function。

from llama_index.vector_stores.milvus.utils import BM25BuiltInFunction

bm25_function = BM25BuiltInFunction(
    analyzer_params={
        "tokenizer": "standard",
        "filter": [
            "lowercase",  # Built-in filter
            {"type": "length", "max": 40},  # Custom cap size of a single token
            {"type": "stop", "stop_words": ["of", "to"]},  # Custom stopwords
        ],
    },
    enable_match=True,
)

vector_store = MilvusVectorStore(
    uri=URI,
    # token=TOKEN,
    dim=1536,
    enable_sparse=True,
    sparse_embedding_function=bm25_function,  # BM25 with custom analyzer
    overwrite=True,
)
2025-04-17 03:38:48,085 [DEBUG][_create_connection]: Created new connection using: 61afd81600cb46ee89f887f16bcbfe55 (async_milvus_client.py:547)

使用其他稀疏嵌入的混合搜索

除了将语义搜索与 BM25 结合外,Milvus 还支持使用 BGE-M3 等稀疏嵌入函数进行混合搜索。以下示例使用内置的 BGEM3SparseEmbeddingFunction 生成稀疏嵌入。

首先,我们需要安装 FlagEmbedding 包:

! pip install -q FlagEmbedding

然后,我们使用默认 OpenAI 模型进行稠密嵌入,并使用内置 BGE-M3 进行稀疏嵌入,构建向量存储和索引:

from llama_index.vector_stores.milvus.utils import BGEM3SparseEmbeddingFunction

vector_store = MilvusVectorStore(
    uri=URI,
    # token=TOKEN,
    dim=1536,
    enable_sparse=True,
    sparse_embedding_function=BGEM3SparseEmbeddingFunction(),
    overwrite=True,
)

storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(
    documents, storage_context=storage_context
)
Fetching 30 files: 100%|██████████| 30/30 [00:00<00:00, 68871.99it/s]
2025-04-17 03:39:02,074 [DEBUG][_create_connection]: Created new connection using: ff4886e2f8da44e08304b748d9ac9b51 (async_milvus_client.py:547)
Chunks: 100%|██████████| 1/1 [00:00<00:00,  1.07it/s]

现在,让我们用一个示例问题执行混合搜索查询:

query_engine = index.as_query_engine(
    vector_store_query_mode="hybrid", similarity_top_k=5
)
response = query_engine.query("What did the author learn at Viaweb??")
print(textwrap.fill(str(response), 100))
Chunks: 100%|██████████| 1/1 [00:00<00:00, 17.29it/s]

The author learned about retail, the importance of user feedback, the value of growth rate in a
startup, the significance of pricing strategy, the benefits of working on things that weren't
prestigious, and the challenges and rewards of running a startup.

自定义稀疏嵌入函数

你还可以自定义稀疏嵌入函数,只要它继承自 BaseSparseEmbeddingFunction,包括以下方法:

  • encode_queries:此方法将文本转换为用于查询的稀疏嵌入列表。
  • encode_documents:此方法将文本转换为用于文档的稀疏嵌入列表。

每个方法的输出应遵循稀疏嵌入的格式,即字典列表。每个字典应有一个表示维度的键(整数),以及一个表示嵌入在该维度上大小的对应值(浮点数)(例如 {1: 0.5, 2: 0.3})。

例如,以下是使用 BGE-M3 的自定义稀疏嵌入函数实现:

from FlagEmbedding import BGEM3FlagModel
from typing import List
from llama_index.vector_stores.milvus.utils import BaseSparseEmbeddingFunction

class ExampleEmbeddingFunction(BaseSparseEmbeddingFunction):
    def __init__(self):
        self.model = BGEM3FlagModel("BAAI/bge-m3", use_fp16=False)

    def encode_queries(self, queries: List[str]):
        outputs = self.model.encode(
            queries,
            return_dense=False,
            return_sparse=True,
            return_colbert_vecs=False,
        )["lexical_weights"]
        return [self._to_standard_dict(output) for output in outputs]

    def encode_documents(self, documents: List[str]):
        outputs = self.model.encode(
            documents,
            return_dense=False,
            return_sparse=True,
            return_colbert_vecs=False,
        )["lexical_weights"]
        return [self._to_standard_dict(output) for output in outputs]

    def _to_standard_dict(self, raw_output):
        result = {}
        for k in raw_output:
            result[int(k)] = raw_output[k]
        return result

自定义混合重排序器

Milvus 支持两种类型的重排序策略:倒数排名融合(RRF)和加权评分。MilvusVectorStore 混合搜索中的默认重排序器是 k=60 的 RRF。要自定义混合重排序器,请修改以下参数:

  • hybrid_ranker (str):指定混合搜索查询中使用的重排序器类型。目前仅支持 [“RRFRanker”, “WeightedRanker”]。默认为 “RRFRanker”。

  • hybrid_ranker_params (dict, optional):混合重排序器的配置参数。此字典的结构取决于所使用的具体重排序器:

    • 对于 “RRFRanker”,它应包含:

      • “k” (int):用于倒数排名融合(RRF)的参数。此值用于在 RRF 算法中计算排名分数,该算法将多种排名策略合并为一个分数,以提高搜索相关性。如果未指定,默认值为 60。
    • 对于 “WeightedRanker”,它需要:

      • “weights”(浮点数列表):一个恰好包含两个权重的列表:

        1. 稠密嵌入分量的权重。
        2. 稀疏嵌入分量的权重。这些权重用于在混合检索过程中平衡嵌入的稠密和稀疏分量的重要性。如果未指定,默认权重为 [1.0, 1.0]。
vector_store = MilvusVectorStore(
    uri=URI,
    # token=TOKEN,
    dim=1536,
    overwrite=False,  # Use the existing collection created in the previous example
    enable_sparse=True,
    hybrid_ranker="WeightedRanker",
    hybrid_ranker_params={"weights": [1.0, 0.5]},
)
index = VectorStoreIndex.from_vector_store(vector_store)
query_engine = index.as_query_engine(
    vector_store_query_mode="hybrid", similarity_top_k=5
)
response = query_engine.query("What did the author learn at Viaweb?")
print(textwrap.fill(str(response), 100))
2025-04-17 03:44:00,419 [DEBUG][_create_connection]: Created new connection using: 09c051fb18c04f97a80f07958856587b (async_milvus_client.py:547)
Sparse embedding function is not provided, using default.
No built-in function detected, using BGEM3SparseEmbeddingFunction().
Fetching 30 files: 100%|██████████| 30/30 [00:00<00:00, 136622.28it/s]
Chunks: 100%|██████████| 1/1 [00:00<00:00,  1.07it/s]

The author learned several valuable lessons at Viaweb, including the importance of understanding
growth rate as the ultimate test of a startup, the significance of user feedback in shaping the
software, and the realization that web applications were the future of software development.
Additionally, the experience at Viaweb taught the author about the challenges and rewards of running
a startup, the value of simplicity in software design, and the impact of pricing strategies on
attracting customers.

BytesRouter 是社区翻译站点,所有译文仅供参考,一切以官方英文原文为准。