首页
/ LlamaIndex 实战:使用 MongoDBAtlasBM25Retriever 在 MongoDB Atlas 上构建 BM25 关键词检索

LlamaIndex 实战:使用 MongoDBAtlasBM25Retriever 在 MongoDB Atlas 上构建 BM25 关键词检索

2026-09-09 09:18:17作者:裴麒琰

导读

MongoDB Atlas 自带的全文检索(Atlas Search)提供了开箱即用的 BM25 相关性评分能力,而 LlamaIndex 生态通过 MongoDBAtlasBM25Retriever 将其封装为标准的 LlamaIndex Retriever。本篇文章以 docs/api_reference/api_reference/retrievers/mongodb_atlas_bm25_retriever.md 中指向的核心类为主线,结合仓库内该集成的完整源码、依赖声明与测试用例,系统讲解其安装方式、构造参数、内部聚合管道与节点重建原理。读完本文,你将掌握如何在 LlamaIndex 应用中直接以 MongoDB 文档为数据源,通过一条 retrieve() 调用完成基于 BM25 的关键词召回,并理解其与向量检索在架构定位上的差异。

一、MongoDBAtlasBM25Retriever 是什么

MongoDBAtlasBM25Retriever 是 LlamaIndex 为 MongoDB Atlas 提供的 BM25 检索器集成,位于仓库的 llama-index-integrations/retrievers/llama-index-retrievers-mongodb-atlas-bm25-retriever/ 目录下。与同为 Atlas 家族的 MongoDBAtlasVectorSearch 不同,后者是一个 VectorStore(负责存储与向量检索),而前者是一个标准的 BaseRetriever 子类,专责于"给定查询字符串,返回带 BM25 相关性分数的节点列表"。

从源码继承关系看(base.py),该类直接继承自 LlamaIndex 核心的 BaseRetriever(定义于 base_retriever.py),因此它天然获得核心框架提供的 retrieve() 公共入口、回调(callback)、dispatcher span 追踪等能力。测试用例 test_retrievers_bm25_retriever.py 中即通过检查 MongoDBAtlasBM25Retriever.__mro__ 断言其基类链中包含 BaseRetriever,从侧面印证了这一设计约定。

二、安装与依赖环境

该集成以独立 Python 包的形式发布,包名为 llama-index-retrievers-mongodb-atlas-bm25-retriever。根据 pyproject.toml 声明的依赖约束:

  • pymongo>=4.6.1,<5:MongoDB 官方 Python 驱动,是连接 Atlas 与执行聚合管道的底层依赖;
  • llama-index-core>=0.13.0,<0.15:提供 BaseRetrieverNodeWithScoreQueryBundleTextNode 等核心类型;
  • requires-python = ">=3.10,<4.0":要求 Python 3.10 及以上版本。

安装方式为标准的 pip 安装:

pip install llama-index-retrievers-mongodb-atlas-bm25-retriever

源码实现中(base.py)对 pymongo 做了延迟导入检查:若环境中缺少 pymongo,会抛出 ImportError 并提示 pip install pymongo,因此在安装上述集成包时请确保 pymongo 一并就绪。

三、快速上手:三步完成 BM25 检索

集成包的 README(README.md)给出了一段可直接运行的示例。它基于 pymongo.MongoClient 建立连接,然后构造检索器并调用 retrieve

from llama_index.retrievers.mongodb_atlas_bm25_retriever import MongoDBAtlasBM25Retriever
import pymongo

mongodb_client = pymongo.MongoClient(mongo_uri)

retriever = MongoDBAtlasBM25Retriever(
    mongodb_client=mongodb_client,
    db_name="vectorstore",
    collection_name="vector_collection",
    index_name="index_vector_collection",
)
nodes = retriever.retrieve("retrieve_query")

其中 mongo_uri 是连接串(形如 mongodb+srv://user:pass@cluster.mongodb.net/),db_namecollection_name 对应你在 Atlas 中已存在的数据库与集合,index_name 则是你在 Atlas Search 中预先创建好的全文索引名称。retrieve() 的入参可以是普通字符串,也可以是 QueryBundle 对象——核心的 BaseRetriever.retrievebase_retriever.py)会自动完成字符串到 QueryBundle 的包装,并交由子类实现的 _retrieve 完成真正的检索逻辑。

四、构造参数详解

MongoDBAtlasBM25Retriever.__init__ 的全部参数及语义(依据 base.py)整理如下:

参数 默认值 说明
mongodb_client None 已创建的 pymongo.MongoClient 实例。若不传,则回退读取环境变量 MONGO_URI 自动创建客户端
db_name "default_db" MongoDB 数据库名
collection_name "default_collection" MongoDB 集合名
index_name "default" Atlas Search 全文索引名(对应 $search 阶段中的 index 字段)
text_key "text" 存放检索文本的文档字段名
metadata_key "metadata" 存放节点元数据的文档字段名
similarity_top_k DEFAULT_SIMILARITY_TOP_K(值为 2) 返回的命中节点数量上限

关于默认值需要特别说明两点:

  1. similarity_top_k 的默认值并非硬编码,而是引用核心常量 DEFAULT_SIMILARITY_TOP_K。该常量定义于 constants.py,取值为 2。也就是说,若不显式指定,检索默认只返回 2 条结果,实际使用中通常需要按业务显式调大。
  2. 客户端创建的双路径逻辑:当 mongodb_clientNone 时,源码会检查环境变量 MONGO_URI 是否存在,不存在则抛出 ValueError;存在则以该 URI 新建客户端,并通过 DriverInfo(name="llama-index", version=version("llama-index")) 向 MongoDB 服务端上报驱动标识,便于 Atlas 侧统计与排障。

五、底层原理:一次 BM25 检索的聚合管道

MongoDBAtlasBM25Retriever._retrievebase.py)的核心是构造并执行一条 MongoDB 聚合管道(aggregation pipeline),完整还原如下:

pipeline = [
    {
        "$search": {
            "index": self._index_name,
            "text": {"query": query, "path": self._text_key},
        }
    },
    {"$addFields": {"score": {"$meta": "searchScore"}}},
    {"$sort": {"score": -1}},
    {"$limit": self._similarity_top_k},
]

results = list(self._collection.aggregate(pipeline))

管道四个阶段各自的作用:

  1. $search:调用 Atlas Search 的 text 查询,index 指定搜索索引名,query 为查询字符串,path 指定要检索的文本字段(即构造参数 text_key)。BM25 相关性评分在这一步由 Atlas Search 引擎完成;
  2. $addFields:通过 $meta: "searchScore" 将 Atlas Search 计算的 BM25 分数写入新增的 score 字段;
  3. $sort:按 score 降序排列,实现相关性从高到低;
  4. $limit:截取前 similarity_top_k 条,控制返回规模。

随后,代码对每个命中文档执行 self._collection.find_one({"_id": result["_id"]}) 回查完整文档,再进入节点重建环节。整条链路完全在 MongoDB 侧完成排序与截断,LlamaIndex 侧只负责组装管道与解析结果,因此检索性能与数据规模主要由 Atlas Search 的索引与集群规格决定。

六、从 MongoDB 文档到 LlamaIndex 节点:元数据重建机制

检索结果需要还原为 LlamaIndex 的 Node 才能被下游的 RetrieverQueryEngine、响应合成器等组件消费。_retrieve 中的重建逻辑(base.py)采用"优先精确还原、失败降级兜底"的两级策略:

  • 第一级(精确还原):读取文档中 metadata 字段里的 _node_content,调用核心工具函数 metadata_dict_to_node(定义于 vector_stores/utils.py)将序列化的节点 JSON 还原为原始的 BaseNode 子类对象(如 TextNodeIndexNode),随后用 node.set_content(doc["text"]) 回填文本内容。这要求数据在写入集合时遵循 LlamaIndex 的节点序列化约定(_node_content 中保存 node.model_dump(mode="json") 的结果)。
  • 第二级(降级兜底):当 metadata_dict_to_node_node_content 缺失或损坏抛出异常时,捕获后手动构造 TextNode,其 textid_metadata 分别取自文档的 text 字段、id 字段与 metadata 字段,并尽量从 node_content 中恢复 start_char_idxend_char_idxrelationships 等字段。

最终,每个节点与管道返回的 score 一起包装为 NodeWithScore(node=node, score=result["score"]),以列表形式返回给调用方。这一设计意味着:即使集合中的文档并非由 LlamaIndex 写入(没有 _node_content),检索器也能降级构造出可用的 TextNode,保证了与外部数据源的兼容性。

七、在查询引擎中组合使用

由于 MongoDBAtlasBM25Retriever 实现了标准的 BaseRetriever 接口,它可以直接参与 LlamaIndex 的查询管线。典型用法是与查询引擎组合,将 BM25 召回结果交给 LLM 生成答案:

from llama_index.core.query_engine import RetrieverQueryEngine

query_engine = RetrieverQueryEngine.from_args(retriever=retriever)
response = query_engine.query("你的查询问题")

也可以与向量检索器结合构成混合检索(hybrid search):将 MongoDBAtlasBM25RetrieverMongoDBAtlasVectorSearch 构建的向量检索器分别召回后,通过 QueryFusionRetriever 或自定义的合并后处理器融合两者的结果,从而兼顾关键词精确匹配与语义相似度召回。仓库中的 retrievers 示例目录 提供了多种检索器组合的 Notebook 参考。

八、前提条件与注意事项

  • Atlas Search 索引需预先创建index_name 指向的全文索引必须先在 MongoDB Atlas 控制台(或通过 Atlas API)创建,且索引配置中的 path 应与 text_key 保持一致,否则 $search 阶段会报错;
  • 连接方式二选一:要么显式传入 mongodb_client,要么保证环境变量 MONGO_URI 可用,二者都不满足时会直接抛出 ValueError
  • 默认 top_k 偏小DEFAULT_SIMILARITY_TOP_K 仅为 2,生产场景建议显式传入 similarity_top_k
  • 字段命名约定:若你的文档中文本字段不叫 text、元数据字段不叫 metadata,请通过 text_keymetadata_key 对齐,否则节点重建的降级路径可能拿不到预期内容;
  • 版本兼容:集成包要求 Python ≥ 3.10、pymongo>=4.6.1,<5llama-index-core>=0.13.0,<0.15,请确保环境中版本满足约束。

小结

MongoDBAtlasBM25Retriever 以极小的代码面(一个类、一条聚合管道)把 MongoDB Atlas Search 的 BM25 能力无缝接入 LlamaIndex 检索体系,既可作为独立的关键词检索器,也能与其他检索器组合成混合检索。通过阅读 base.pyREADME.md,你可以完整掌握其参数语义、管道结构与节点重建细节,进而在自己的 RAG 应用中直接复用这一能力。

热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
34
18
docsdocs
暂无描述
Markdown
900
5.83 K
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.15 K
2.77 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.36 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
929
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.94 K
1.03 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
534
603
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.47 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
398
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.05 K
529