LEANN 基线基准测试指南:BM25 与 DiskANN 检索延迟对比
2026/9/15 18:23:47 网站建设 项目流程

LEANN 基线基准测试指南:BM25 与 DiskANN 检索延迟对比

【免费下载链接】LEANN[MLsys2026 Best Paper]: https://arxiv.org/abs/2506.08276. RAG on Everything with LEANN. Enjoy 97% storage savings while running a fast, accurate, and 100% private RAG application on your personal device.项目地址: https://gitcode.com/GitHub_Trending/le/LEANN

LEANN(benchmarks/bm25_diskann_baselines/)提供了一套独立的检索基线基准:一个是基于 Pyserini/Lucene 的 BM25 稀疏检索,另一个是基于 leann-backend-diskann 的 DiskANN 图索引检索。本文将以 benchmarks/bm25_diskann_baselines/README.md 为主线,完整讲解两个基准的索引数据获取、运行命令、参数含义与实测结果,并结合 run_bm25.py、run_diskann.py 与 diskann_backend.py 的源码,深入拆解每个开关背后对延迟与吞吐的影响。读完本文,你将掌握如何在本地复现这套"稀疏基线 vs 图索引基线"的延迟对比,并理解 DiskANN 搜索参数(complexity、beam_width、cache_mechanism 等)的底层语义。

基准定位:为什么要同时测 BM25 与 DiskANN

RAG 系统的检索环节存在两类主流方案:以 BM25 为代表的词法稀疏检索,与以 DiskANN 为代表的向量近似最近邻(ANN)图索引检索。二者在索引结构、查询路径、硬件依赖上差异极大,单独报告任何一方的延迟都缺乏参照系。LEANN 在benchmarks/bm25_diskann_baselines/下同时提供两个独立脚本,用于在同一台机器、同一份查询集上分别测量两种基线的纯检索延迟,作为评估 LEANN 自身检索性能的外部参照。

两个脚本的设计原则(见 README.md 的 Notes 部分):

  • DiskANN 只统计search-only 延迟:查询的 embedding 事先计算好并从计时中剔除;
  • BM25 直接对文本查询做词法检索,天然不涉及 embedding;
  • 两个基准使用同一份真实查询集(Natural Questions,NQ);
  • 结果明确标注为machine-specific(机器相关),仅代表在"当前仓库 + 当前机器"上测得的本地数据。

数据准备:拉取索引与查询集

README 给出的第一步是从 AWS S3 同步两个预构建索引到本地:

aws s3 sync s3://powerrag-diskann-rpj-wiki-20250824-224037-194d640c/bm25_rpj_wiki/index_en_only/ benchmarks/data/indices/bm25_index/ aws s3 sync s3://powerrag-diskann-rpj-wiki-20250824-224037-194d640c/diskann_rpj_wiki/ benchmarks/data/indices/diskann_rpj_wiki/

两条命令分别把:

  • bm25_rpj_wiki/index_en_only/同步到benchmarks/data/indices/bm25_index/(Pyserini 的 Lucene BM25 索引目录);
  • diskann_rpj_wiki/同步到benchmarks/data/indices/diskann_rpj_wiki/(DiskANN 磁盘图索引目录)。

从 bucket 命名中的rpj_wiki可以推断,两个索引均构建自同一份 Wiki 语料(推测为 RedPajama 系列 Wiki 语料,英文子集),且索引前缀默认为ann(对应脚本参数--index-prefix的默认值,磁盘上形如ann_disk.index及相关 PQ 文件)。

查询集固定为benchmarks/data/queries/nq_open.jsonl(Natural Questions 的 open-domain 抽取版),两个脚本默认都指向它。

注意:S3 bucket 中的索引文件不在仓库内,运行基准前需自行执行同步并确保awsCLI 已安装配置。

DiskANN 基线:run_diskann.py

运行命令与结果

uv run --script benchmarks/bm25_diskann_baselines/run_diskann.py

README 记录的本机实测结果:

指标数值
平均延迟0.011093 s/query
QPS90.15
p500.010731 s
p950.015000 s

对应设置(与脚本默认值一致):

  • recompute_embeddings=False:关闭重算重排,只走 PQ 近似搜索路径;
  • embeddings 预计算(use_server=False,不计时);
  • batching off:逐条查询,每次只送 1 个向量(embs[i : i + 1]);
  • 缓存关闭:cache_mechanism=2num_nodes_to_cache=0

脚本机制逐段拆解

run_diskann.py使用 PEP 723 内联元数据声明依赖leann-backend-diskann(run_diskann.py),由uv run --script自动解析执行。

1. 参数面(默认值即 README 记录的基准设置)

参数默认值说明
--index-dirbenchmarks/data/indices/diskann_rpj_wikiDiskANN 索引文件目录
--index-prefixann索引文件前缀(C++ 层会拼出ann_disk.index等文件)
--queries-filebenchmarks/data/queries/nq_open.jsonlNQ 查询集
--num-queries200参与计时的查询条数
--top-k10返回的近邻数
--complexity62搜索候选列表规模(L=62),越大越准越慢
--threads1搜索线程数
--beam-width1每轮并发的 I/O 请求数
--cache-mechanism2缓存机制(见下文源码语义)
--num-nodes-to-cache0缓存节点数,0 即不缓存

2. embedding 预计算(run_diskann.py):

embs = _compute( queries, model_name="facebook/contriever-msmarco", mode="sentence-transformers", use_server=False, ).astype(np.float32)

关键点:模型固定为facebook/contriever-msmarco(与索引构建时的向量空间必须一致),use_server=False表示不走 ZMQ embedding server,直接本地计算。这正是 api.py 中compute_embeddings的分支语义:use_server=True走端口转发给 server(适合查询场景),use_server=Falseembedding_compute的直连计算(适合 build 场景)。预计算完成后向量在计时循环之外,从而保证测到的是纯索引搜索延迟。

3. 构造 Searcher(run_diskann.py):

searcher = _DiskannSearcher( index_prefix_path, num_threads=int(args.threads), cache_mechanism=int(args.cache_mechanism), num_nodes_to_cache=int(args.num_nodes_to_cache), )

底层对应 DiskannSearcher。注意index_prefix_path传的是基础路径(不含_disk.index后缀),C++ 层会自动拼出_disk.index;若目录下检测到*_disk_graph.index*_partition.bin两个分区文件,还会自动启用分区前缀走图分区索引。

4. 计时循环(run_diskann.py):

先跑 1 次 warmup(不计时),然后对每条查询执行:

searcher.search( embs[i : i + 1], # 单条查询,batching off top_k=args.top_k, complexity=args.complexity, beam_width=args.beam_width, prune_ratio=0.0, # 不做近似剪枝 recompute_embeddings=False, batch_recompute=False, dedup_node_dis=False, )

这些开关直接对应 diskann_backend.py 的search签名:

  • complexity:候选列表大小,决定 PQ 距离遍历的广度,是"准确率—延迟"的核心旋钮;
  • beam_width:每轮并行 I/O 请求数,影响磁盘读取的并发度;
  • prune_ratio:用近似距离剪枝邻居的比例(0.0–1.0),基准关闭(0.0);
  • recompute_embeddings=False时走use_deferred_fetch=False的纯 PQ 路径,C++ 层遍历始终用 PQ 距离,不触发重排(见 diskann_backend.py 的策略注释);
  • cache_mechanism的语义在源码中明确注释:1= 用 sample data 初始化缓存,2= 就绪缓存但不初始化,其他值 = 禁用缓存(diskann_backend.py)。基准取2配合num_nodes_to_cache=0,等价于彻底关闭缓存,测的是冷缓存的原始索引访问能力。

结果按 p50/p95 输出(p50 即排序后len(times)//2处的值),QPS 用1.0 / avg计算。

BM25 基线:run_bm25.py

运行命令与结果

uv run --script benchmarks/bm25_diskann_baselines/run_bm25.py

README 记录的本机实测结果:

指标数值
平均延迟0.028589 s/query
QPS34.97
p500.026060 s
p900.043695 s
p950.053260 s
p990.055257 s

对应设置:k=10k1=0.9b=0.4、queries=100。

环境准备:JDK 21 与 Pyserini

run_bm25.py依赖pyserini(Lucene 之上的 Python 检索库),而 Pyserini 需要 JDK。脚本头部注释给出了 Arch Linux 下的完整配置流程(run_bm25.py):

sudo pacman -S jdk21-openjdk export JAVA_HOME=/usr/lib/jvm/java-21-openjdk sudo archlinux-java status sudo archlinux-java set java-21-openjdk # fish shell 下持久化: set -Ux JAVA_HOME /usr/lib/jvm/java-21-openjdk fish_add_path --global $JAVA_HOME/bin set -Ux LD_LIBRARY_PATH $JAVA_HOME/lib/server $LD_LIBRARY_PATH which javac # 应输出 /usr/lib/jvm/java-21-openjdk/bin/javac

其他发行版只需保证JAVA_HOME指向可用的 JDK(21 及以上)即可,脚本会在缺失时提示pip install pyserini

参数面

参数默认值说明
--bm25-indexbenchmarks/data/indices/bm25_indexPyserini Lucene 索引目录
--queriesbenchmarks/data/queries/nq_open.jsonl查询文件
--k10Top-k 检索数
--k10.9BM25 词频饱和参数
--b0.4BM25 文档长度归一化参数
--limit100最多执行的查询条数(README 结果即 100)
--warmup5预热查询数(不计时)
--fetch-docsoff额外抓取命中文档内容(更慢,默认关)
--report可选,输出 JSON 报告路径

脚本机制要点

  • 查询加载(run_bm25.py):优先解析 JSONL,依次尝试query/text/question字段;解析失败的行按纯文本处理;非 JSONL 文件按"每行一条查询"读取。
  • BM25 参数注入(run_bm25.py):LuceneSearcher打开索引后调用searcher.set_bm25(k1=args.k1, b=args.b),部分 pyserini 构建版本不要求显式设置,因此用 try/except 兜底。
  • 计时:先跑warmup条预热,再逐条searcher.search(q, k=args.k)计时;若开--fetch-docs,还会对每个命中调用searcher.doc(h.docid)把文档读取 I/O 计入。
  • 报告--report可把 queries、k、k1、b、avg、p50/p90/p95/p99、total_time、qps、索引绝对路径等结构化写入 JSON(run_bm25.py),便于后续对比分析。

结果对比与解读

把两个基线的 README 结果放到一起:

基线avgQPSp50p95
DiskANN(NQ,search-only)0.011093 s90.150.010731 s0.015000 s
BM25(k=10, k1=0.9, b=0.4)0.028589 s34.970.026060 s0.053260 s

在 README 记录的这台机器上,DiskANN 的纯搜索延迟约为 BM25 的 1/2.6,吞吐约为 2.6 倍。解读时需注意三点:

  1. 口径不同:DiskANN 侧 embedding 已预计算并排除在计时外,BM25 侧则是纯词法打分,两者都是"纯检索",但 DiskANN 的实际端到端延迟还需加上 embedding 计算成本;
  2. 关闭了缓存与重排:DiskANN 的cache_mechanism=2num_nodes_to_cache=0意味着没有利用节点缓存加速,若开启缓存(cache_mechanism=1或更大的num_nodes_to_cache)延迟通常还会进一步下降;
  3. machine-specific:README 明确声明结果是在当前仓库、当前机器上测得的本地数据,不代表通用结论;换机器、换索引、换查询集后数字会变化,复现时应以自身环境为准。

源码纵深:LEANN 内置 BM25 与外部基线的区别

值得说明的是,run_bm25.py使用的 Pyserini/Lucene 是外部独立基线,与 LEANN 自身代码无关。而 LEANN 核心也内置了一个基于 SQLite FTS5 的 BM25 索引Fts5BM25Index(见 api.py):

  • BM25Index抽象基类定义契约:fit(documents)建索引、查询时命中bm25()打分;
  • Fts5BM25IndexCREATE VIRTUAL TABLE bm25_passages USING fts5(...)持久化词项/倒排数据,并在建表时按_cjk_ngrams开关决定是否对中日韩文本做 unigram/bigram 切分(api.py);
  • 由于 SQLite FTS5 的bm25()返回值是"越小越好",LEANN 内部取负号统一成"越大越好"的分数语义,方便与向量分数做混合融合(见 api.py 的注释)。

也就是说:bm25_diskann_baselines目录下的 BM25 基准用于横向对标外部检索实现;如果要在 LEANN 内部做混合检索(sparse + dense),则应使用Fts5BM25Index这条内置路径。二者得分口径、索引后端均不同,做对比实验时不要混用。

复现注意事项

  • 索引不在仓库内:必须先用aws s3 sync拉取benchmarks/data/indices/下的两个索引目录,脚本才会通过目录存在性检查(run_bm25.py检查os.path.isdirrun_diskann.py检查index_dir.is_dir(),否则直接退出);
  • 查询集固定:默认都指向benchmarks/data/queries/nq_open.jsonl,若换用自定义查询文件,需保证向量空间与索引构建时一致(DiskANN 侧为facebook/contriever-msmarco);
  • 环境差异:Pyserini 需要 JDK 21 且JAVA_HOME正确;DiskANN 侧leann-backend-diskann(当前版本 0.3.8,见 pyproject.toml)需随uv run --script自动安装或预装;
  • 结果可复现性:两个脚本都提供 warmup 机制排除冷启动,且run_bm25.py支持--report输出 JSON 报告,建议复现时固定同一批参数并多次运行取稳定值。

通过这套双基线基准,你可以快速在同一环境下回答一个关键问题:给定你的语料与查询分布,"词法稀疏检索"与"图索引向量检索"各自的纯检索延迟处在什么水平,从而为 LEANN 的检索链路选型(或混合检索比例)提供可量化的参照。

【免费下载链接】LEANN[MLsys2026 Best Paper]: https://arxiv.org/abs/2506.08276. RAG on Everything with LEANN. Enjoy 97% storage savings while running a fast, accurate, and 100% private RAG application on your personal device.项目地址: https://gitcode.com/GitHub_Trending/le/LEANN

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询