LlamaIndex 实战:使用 MongoDBAtlasBM25Retriever 在 MongoDB Atlas 上构建 BM25 关键词检索
【免费下载链接】llama_indexLlamaIndex is the leading document agent and OCR platform项目地址: https://gitcode.com/GitHub_Trending/ll/llama_index
导读
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:提供BaseRetriever、NodeWithScore、QueryBundle、TextNode等核心类型;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_name、collection_name对应你在 Atlas 中已存在的数据库与集合,index_name则是你在 Atlas Search 中预先创建好的全文索引名称。retrieve()的入参可以是普通字符串,也可以是QueryBundle对象——核心的BaseRetriever.retrieve(base_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) | 返回的命中节点数量上限 |
关于默认值需要特别说明两点:
similarity_top_k的默认值并非硬编码,而是引用核心常量DEFAULT_SIMILARITY_TOP_K。该常量定义于 constants.py,取值为2。也就是说,若不显式指定,检索默认只返回 2 条结果,实际使用中通常需要按业务显式调大。- 客户端创建的双路径逻辑:当
mongodb_client为None时,源码会检查环境变量MONGO_URI是否存在,不存在则抛出ValueError;存在则以该 URI 新建客户端,并通过DriverInfo(name="llama-index", version=version("llama-index"))向 MongoDB 服务端上报驱动标识,便于 Atlas 侧统计与排障。
五、底层原理:一次 BM25 检索的聚合管道
MongoDBAtlasBM25Retriever._retrieve(base.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))管道四个阶段各自的作用:
$search:调用 Atlas Search 的text查询,index指定搜索索引名,query为查询字符串,path指定要检索的文本字段(即构造参数text_key)。BM25 相关性评分在这一步由 Atlas Search 引擎完成;$addFields:通过$meta: "searchScore"将 Atlas Search 计算的 BM25 分数写入新增的score字段;$sort:按score降序排列,实现相关性从高到低;$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子类对象(如TextNode、IndexNode),随后用node.set_content(doc["text"])回填文本内容。这要求数据在写入集合时遵循 LlamaIndex 的节点序列化约定(_node_content中保存node.model_dump(mode="json")的结果)。 - 第二级(降级兜底):当
metadata_dict_to_node因_node_content缺失或损坏抛出异常时,捕获后手动构造TextNode,其text、id_、metadata分别取自文档的text字段、id字段与metadata字段,并尽量从node_content中恢复start_char_idx、end_char_idx、relationships等字段。
最终,每个节点与管道返回的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):将MongoDBAtlasBM25Retriever与MongoDBAtlasVectorSearch构建的向量检索器分别召回后,通过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_key、metadata_key对齐,否则节点重建的降级路径可能拿不到预期内容; - 版本兼容:集成包要求 Python ≥ 3.10、
pymongo>=4.6.1,<5、llama-index-core>=0.13.0,<0.15,请确保环境中版本满足约束。
小结
MongoDBAtlasBM25Retriever以极小的代码面(一个类、一条聚合管道)把 MongoDB Atlas Search 的 BM25 能力无缝接入 LlamaIndex 检索体系,既可作为独立的关键词检索器,也能与其他检索器组合成混合检索。通过阅读 base.py 与 README.md,你可以完整掌握其参数语义、管道结构与节点重建细节,进而在自己的 RAG 应用中直接复用这一能力。
【免费下载链接】llama_indexLlamaIndex is the leading document agent and OCR platform项目地址: https://gitcode.com/GitHub_Trending/ll/llama_index
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考