# https://github.com/xhluca/bm25s 项目说明书

生成时间：2026-06-28 11:30:07 UTC

## 目录

- [项目概览、安装与快速开始](#page-1)
- [核心 API：BM25 类、分词器与评分变体](#page-2)
- [性能优化：Numba 后端、内存映射与 Hugging Face 集成](#page-3)
- [CLI、High-Level API、MCP 服务器、持久化与已知问题](#page-4)

<a id='page-1'></a>

## 项目概览、安装与快速开始

### 相关页面

相关主题：[核心 API：BM25 类、分词器与评分变体](#page-2)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/xhluca/bm25s/blob/main/README.md)
- [setup.py](https://github.com/xhluca/bm25s/blob/main/setup.py)
- [bm25s/__init__.py](https://github.com/xhluca/bm25s/blob/main/bm25s/__init__.py)
- [bm25s/high_level/__init__.py](https://github.com/xhluca/bm25s/blob/main/bm25s/high_level/__init__.py)
- [bm25s/high_level/README.md](https://github.com/xhluca/bm25s/blob/main/bm25s/high_level/README.md)
- [bm25s/hf.py](https://github.com/xhluca/bm25s/blob/main/bm25s/hf.py)
- [bm25s/scoring.py](https://github.com/xhluca/bm25s/blob/main/bm25s/scoring.py)
- [bm25s/stopwords.py](https://github.com/xhluca/bm25s/blob/main/bm25s/stopwords.py)
- [examples/save_and_reload_end_to_end.py](https://github.com/xhluca/bm25s/blob/main/examples/save_and_reload_end_to_end.py)
- [examples/index_nq.py](https://github.com/xhluca/bm25s/blob/main/examples/index_nq.py)
</details>

# 项目概览、安装与快速开始

## 项目概览

`bm25s` 是一个用纯 Python 实现的高性能 BM25 检索库，依赖 SciPy 稀疏矩阵来预存评分数据，从而在查询阶段获得数量级的速度提升。它不依赖 Java 或 PyTorch，仅需 NumPy 作为基础依赖，并可选地集成轻量的词干提取（Stemmer）与停用词处理能力。

资料来源：[README.md:1-40]()

BM25 是一种被 Elasticsearch 等搜索引擎广泛使用的经典排序算法，用于根据关键词匹配度对文档进行打分。`bm25s` 在此基础上提供了完整的变体支持，包括 `robertson`、`atire`、`bm25l`、`bm25+` 与默认的 `lucene`，可通过 `BM25(method=...)` 参数切换。资料来源：[README.md:200-220]()

社区中曾有讨论（参见 Issue #80）指出本库的评分机制与早期 [bm25_pt](https://github.com/jxmorris12/bm25_pt) 项目存在 API 相似性，开发者已在文档中对此致谢。

## 安装

### 通过 pip 安装

最简安装方式：

```bash
pip install bm25s
```

资料来源：[setup.py:1-30]()

`setup.py` 中仅将 `numpy` 列为必需依赖，因此默认安装保持精简。

### 可选依赖

`setup.py` 通过 `extras_require` 提供多组可选依赖，对应不同的使用场景：

| 扩展名 | 用途 |
|--------|------|
| `core` | 包含基础分词、索引与 BEIR 评测所需依赖 |
| `full` | 包含 `core` 与 PyStemmer 等词干提取能力 |
| `stemmer` | 仅安装 PyStemmer |
| `mcp` | 启用内置的 Model Context Protocol 服务端 |
| `dev` | 测试与开发工具链 |

资料来源：[setup.py:1-30]()、[README.md:130-160]()

例如启动 MCP 服务器需先执行 `pip install "bm25s[mcp]"`。资料来源：[README.md:130-160]()

## 快速开始

### 高级 API（推荐）

对于初学者，官方推荐使用 [`BM25` 包](https://pypi.org/project/BM25/)（一键安装并启用词干、CLI），其内部仍由 `bm25s` 提供性能保障：

```python
import BM25

corpus = BM25.load("documents.csv", document_column="text")
retriever = BM25.index(corpus)

results = retriever.search(["how to learn python"], k=5)
for r in results[0]:
    print(f"Score: {r['score']:.2f} | Document: {r['document']}")
```

资料来源：[bm25s/high_level/README.md:30-60]()

若直接使用 `bm25s` 自带的 `bm25s.high_level`，调用方式一致：`bm25.load(...)` 负责读取 csv/json/jsonl/txt 文件，`bm25.index(...)` 完成分词与建索引。

资料来源：[bm25s/high_level/__init__.py:60-130]()

### 底层 API

需要更细粒度控制时，可直接使用 `bm25s.BM25` 与 `Tokenizer`：

```python
import bm25s
from bm25s.tokenization import Tokenizer

corpus = ["BM25 is a widely used ranking function.",
          "bm25s is fast and easy to use."]

tokenizer = Tokenizer(stopwords="english", stemmer=Stemmer.Stemmer("english"))
corpus_tokens = tokenizer.tokenize(corpus, return_as="tuple")

retriever = bm25s.BM25(corpus=corpus)
retriever.index(corpus_tokens)

queries = ["fast ranking"]
query_tokens = tokenizer.tokenize(queries, update_vocab=False)
results, scores = retriever.retrieve(query_tokens, k=2)
```

资料来源：[README.md:40-80]()、[bm25s/__init__.py:1-50]()

需要注意：底层 API 的 `corpus` 入参支持字符串、字典、列表或元组；若元素既不是字符串也无法序列化为 JSON，会被跳过并记录警告。资料来源：[bm25s/__init__.py:200-260]()

社区 Issue #158 也提醒用户注意，`corpus` 既可以是字符串列表，也可以是字典列表（包含 `id`、`text` 等任意键），两种格式都被 `bm25s` 接受。

## 索引持久化与重载

通过 `retriever.save(save_dir)` 与 `tokenizer.save_vocab(save_dir)` 可将索引与词表写入磁盘，随后用 `bm25s.BM25.load(save_dir, load_corpus=True)` 与 `tokenizer.load_vocab(save_dir)` 恢复，从而避免重复构建大语料库的索引。

资料来源：[examples/save_and_reload_end_to_end.py:1-50]()、[bm25s/__init__.py:260-340]()

## 命令行与 MCP 集成

`setup.py` 注册了控制台入口 `bm25`，可使用 `bm25 mcp launch --port 8000 --index-dir <dir>` 启动 MCP 服务器，把已有 BM25 索引暴露为 LLM 工具。资料来源：[setup.py:1-30]()、[README.md:130-170]()

也可结合 HuggingFace Hub：使用 `BM25HF.save_to_hub(...)` 与 `BM25HF.load_from_hub(repo_id)` 即可上传或拉取远程索引。资料来源：[bm25s/hf.py:1-60]()

## 已知问题与注意事项

在 Windows 平台上，`bm25s.utils.benchmark` 模块曾因尝试导入仅 Unix 可用的 `resource` 模块而向 stdout 输出警告信息，影响 MCP 健康检查（Issue #186、#178）。该问题已在 0.3.9 版本中通过将日志级别降级为 `debug` 修复，建议用户保持版本更新。

## See Also

- BM25 评分公式与变体详解：[scoring.py](https://github.com/xhluca/bm25s/blob/main/bm25s/scoring.py)
- 大规模语料库索引示例：[examples/index_nq.py](https://github.com/xhluca/bm25s/blob/main/examples/index_nq.py)
- 多语言停用词列表：[bm25s/stopwords.py](https://github.com/xhluca/bm25s/blob/main/bm25s/stopwords.py)

---

<a id='page-2'></a>

## 核心 API：BM25 类、分词器与评分变体

### 相关页面

相关主题：[项目概览、安装与快速开始](#page-1), [性能优化：Numba 后端、内存映射与 Hugging Face 集成](#page-3)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [bm25s/__init__.py](https://github.com/xhluca/bm25s/blob/main/bm25s/__init__.py)
- [bm25s/scoring.py](https://github.com/xhluca/bm25s/blob/main/bm25s/scoring.py)
- [bm25s/high_level/__init__.py](https://github.com/xhluca/bm25s/blob/main/bm25s/high_level/__init__.py)
- [bm25s/hf.py](https://github.com/xhluca/bm25s/blob/main/bm25s/hf.py)
- [bm25s/stopwords.py](https://github.com/xhluca/bm25s/blob/main/bm25s/stopwords.py)
- [README.md](https://github.com/xhluca/bm25s/blob/main/README.md)
- [examples/save_and_reload_end_to_end.py](https://github.com/xhluca/bm25s/blob/main/examples/save_and_reload_end_to_end.py)
- [setup.py](https://github.com/xhluca/bm25s/blob/main/setup.py)
</details>

# 核心 API：BM25 类、分词器与评分变体

## 概览

`bm25s` 是一个纯 Python 实现的 BM25 排序库，其核心 API 由两个类组成：[`BM25`](https://github.com/xhluca/bm25s/blob/main/bm25s/__init__.py) 负责建立与检索词项-文档评分矩阵，[`Tokenizer`](https://github.com/xhluca/bm25s/blob/main/bm25s/tokenization.py) 负责将原始文本转换为词项 ID 序列。两者解耦，使得用户可以独立控制分词策略与排序变体。

项目同时提供 [`bm25s.high_level`](https://github.com/xhluca/bm25s/blob/main/bm25s/high_level/__init__.py) 模块作为“一行式”封装，并在 [`README.md`](https://github.com/xhluca/bm25s/blob/main/README.md) 中明确建议：若追求更简洁的体验，可改用上游 `BM25` 包（PyPI 上的 `BM25`），它会自动安装 `bm25s` 作为后端。

```mermaid
flowchart LR
  A[原始语料 Corpus] --> B[Tokenizer.tokenize]
  B --> C[词项 ID 元组 / 生成器]
  C --> D[BM25.index]
  D --> E[CSC 稀疏评分矩阵<br/>scores.data/indices/indptr]
  E --> F[BM25.retrieve / mmap 检索]
  G[query 文本] --> B
  F --> H[Top-k 文档及分数]
```

## BM25 类：索引与检索

### 构造与索引构建

`BM25` 的核心思想是“急切稀疏评分”（eager sparse scoring）：在 `index()` 阶段就为每个词项-文档对预计算 BM25 分数，并存储为 CSC 稀疏矩阵，查询时仅做轻量级的切片与排序 ([bm25s/__init__.py](https://github.com/xhluca/bm25s/blob/main/bm25s/__init__.py))。

构造时常用的关键参数包括：

| 参数 | 作用 | 默认 |
|---|---|---|
| `method` | 评分变体：`robertson` / `atire` / `bm25l` / `bm25+` / `lucene` | `lucene` |
| `idf_method` | 单独控制 IDF 计算公式 | 同 `method` |
| `k1`, `b` | BM25 饱和与长度归一化参数 | `1.5`, `0.75` |
| `delta` | `bm25l` / `bm25+` 专用 | `0.5` |
| `backend` | 评分计算后端（`numba` / 纯 Python） | 视安装而定 |
| `csc_backend` | 稀疏矩阵构造后端：`scipy` / `numpy` | `scipy` |

`index()` 内部会调用 [`_build_scores_and_indices_for_matrix`](https://github.com/xhluca/bm25s/blob/main/bm25s/__init__.py) 来生成 `(data, indices, indptr)`，再交由 `_np_csc` 或 `sp.csc_matrix` 装配为最终的稀疏矩阵 ([bm25s/__init__.py](https://github.com/xhluca/bm25s/blob/main/bm25s/__init__.py))。

### 检索、持久化与 mmap

检索接口 `BM25.retrieve(token_ids, k=...)` 直接在已构建的 CSC 矩阵上做高效切片；可通过 `return_as` 控制返回值形态（`(documents, scores)`、`tuple` 或 `documents`），并支持以 `titles` 等替代语料返回字符串 ([README.md](https://github.com/xhluca/bm25s/blob/main/README.md))。

`BM25.save()` / `BM25.load()` 支持把索引与原始语料一并落盘，并通过 `mmap=True` 启用内存映射，避免大语料全部加载到 RAM；分词器需单独调用 `tokenizer.save_vocab()` 与 `tokenizer.load_vocab()`，示例见 [`examples/save_and_reload_end_to_end.py`](https://github.com/xhluca/bm25s/blob/main/examples/save_and_reload_end_to_end.py)。`corpus` 参数若为字符串则按行写入 `corpus.jsonl`，字典/列表/元组则原样写出 ([README.md](https://github.com/xhluca/bm25s/blob/main/README.md))。

社区曾反馈语料格式不一致的问题（[#158](https://github.com/xhluca/bm25s/issues/158)）：文档明确 `corpus` 既可以是字符串列表，也可以是 `{"id", "text"}` 字典列表，后者更便于与 BEIR 等评测流程对接 ([bm25s/__init__.py](https://github.com/xhluca/bm25s/blob/main/bm25s/__init__.py))。

### 后端选择与 Numba

`backend="numba"` 在版本 0.2.0 起作为默认推荐，可带来约 2× 的吞吐提升 ([README.md](https://github.com/xhluca/bm25s/blob/main/README.md))。[`bm25s/high_level/__init__.py`](https://github.com/xhluca/bm25s/blob/main/bm25s/high_level/__init__.py) 中封装的默认即 `backend="numba", csc_backend="numpy", auto_compile=False`，以避免首次调用时的编译延迟。

## Tokenizer：分词、词表与停用词

`Tokenizer` 与 `BM25` 互相独立：用户先调用 `tokenize(corpus, return_as="tuple" | "ids" | "strings")` 得到词项序列，再交给 `BM25.index()` ([examples/save_and_reload_end_to_end.py](https://github.com/xhluca/bm25s/blob/main/examples/save_and_reload_end_to_end.py))。

可配置项包括：
- `splitter`：可调用对象，按文档切词；
- `stemmer`：任意可调用函数（如 `Stemmer.Stemmer("english")`），对词项列表做词干化；
- `stopwords`：字符串（语言名）或显式词表；内置多语言停用词来自 [NLTK stopwords 列表](https://github.com/xhluca/bm25s/blob/main/bm25s/stopwords.py)；
- `lower`：是否在分词前小写化，默认在高层 API 中为 `True` ([bm25s/high_level/__init__.py](https://github.com/xhluca/bm25s/blob/main/bm25s/high_level/__init__.py))。

查询时可通过 `update_vocab=False` 复用已训练词表，避免把查询词误写入索引；`save_vocab()` / `save_stopwords()` 则用于跨进程恢复 ([examples/save_and_reload_end_to_end.py](https://github.com/xhluca/bm25s/blob/main/examples/save_and_reload_end_to_end.py))。需要注意，`bm25s.high_level` 目前仅实现 `language="english"` 分支，其他语言会直接抛 `NotImplementedError` ([bm25s/high_level/__init__.py](https://github.com/xhluca/bm25s/blob/main/bm25s/high_level/__init__.py))；但底层 `Tokenizer` 与 [stopwords.py](https://github.com/xhluca/bm25s/blob/main/bm25s/stopwords.py) 已包含中文等多语言停用词，可通过核心 API 自行组装。

## 评分变体

`bm25s` 在 [`scoring.py`](https://github.com/xhluca/bm25s/blob/main/bm25s/scoring.py) 中实现了五种 BM25 变体，参见 [Kamphuis et al. 2020](https://link.springer.com/chapter/10.1007/978-3-030-45442-5_4)：

- `robertson`：原始实现，但将负 IDF 截断为 0；
- `atire`：ATIRE 实现；
- `bm25l` / `bm25+`：需要额外的 `delta` 参数，库内会额外构建 `nonoccurrence_array` 用于补偿未出现的词项 ([bm25s/scoring.py](https://github.com/xhluca/bm25s/blob/main/bm25s/scoring.py))；
- `lucene`：与 Apache Lucene 的默认实现完全等价，也是 `bm25s` 的默认 `method`。

需要注意的是，IDF 与 TF 的公式可以分开指定：`idf_method` 可独立于 `method` 设置，从而复现 `rank-bm25` 的默认行为（IR 教材推荐 `k1 ∈ [1.2, 2.0]`，`b=0.75`）([README.md](https://github.com/xhluca/bm25s/blob/main/README.md))。

评分机制的“急切打分”思路源自 [`bm25_pt`](https://github.com/jxmorris12/bm25_pt)，`BM25` 类的 API 也借鉴了 `rank-bm25` 的设计（[#80](https://github.com/xhluca/bm25s/issues/80)）；Numba 内核则参考了 [baguetter](https://github.com/mixedbread-ai/baguetter) 与 [retriv](https://github.com/AmenRa/retriv) ([README.md](https://github.com/xhluca/bm25s/blob/main/README.md))。

## See Also

- 高级封装与 CLI：[`bm25s/high_level`](https://github.com/xhluca/bm25s/blob/main/bm25s/high_level/__init__.py)
- Hugging Face Hub 集成：[`bm25s/hf.py`](https://github.com/xhluca/bm25s/blob/main/bm25s/hf.py)
- 大规模索引示例：[`examples/index_nq.py`](https://github.com/xhluca/bm25s/blob/main/examples/index_nq.py)
- MCP 服务：[`examples/mcp/`](https://github.com/xhluca/bm25s/blob/main/examples/mcp/create_index.py)
- 安装与可选依赖：[`setup.py`](https://github.com/xhluca/bm25s/blob/main/setup.py)

---

<a id='page-3'></a>

## 性能优化：Numba 后端、内存映射与 Hugging Face 集成

### 相关页面

相关主题：[核心 API：BM25 类、分词器与评分变体](#page-2), [CLI、High-Level API、MCP 服务器、持久化与已知问题](#page-4)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [bm25s/numba/__init__.py](https://github.com/xhluca/bm25s/blob/main/bm25s/numba/__init__.py)
- [bm25s/numba/retrieve_utils.py](https://github.com/xhluca/bm25s/blob/main/bm25s/numba/retrieve_utils.py)
- [bm25s/numba/selection.py](https://github.com/xhluca/bm25s/blob/main/bm25s/numba/selection.py)
- [bm25s/hf.py](https://github.com/xhluca/bm25s/blob/main/bm25s/hf.py)
- [bm25s/utils/benchmark.py](https://github.com/xhluca/bm25s/blob/main/bm25s/utils/benchmark.py)
- [examples/index_and_retrieve_with_numba.py](https://github.com/xhluca/bm25s/blob/main/examples/index_and_retrieve_with_numba.py)
- [bm25s/high_level/__init__.py](https://github.com/xhluca/bm25s/blob/main/bm25s/high_level/__init__.py)
- [examples/save_and_reload_end_to_end.py](https://github.com/xhluca/bm25s/blob/main/examples/save_and_reload_end_to_end.py)
- [README.md](https://github.com/xhluca/bm25s/blob/main/README.md)
- [setup.py](https://github.com/xhluca/bm25s/blob/main/setup.py)
</details>

# 性能优化：Numba 后端、内存映射与 Hugging Face 集成

## 概述

`bm25s` 围绕"快速检索 + 易分发"的目标，在评分计算、索引存取与远程共享三个层面提供了可组合的优化路径。检索阶段通过预计算 Scipy 稀疏矩阵并在查询时仅做矩阵切片与归并来避免重复计算；评分核心通过 `numba` JIT 后端将 Python 热点循环编译为机器码以提升吞吐；索引则通过 `numpy.savez` 等格式落盘并支持从 Hugging Face Hub 直接拉取，从而把"建好的索引"作为可复用的工件分发出去。资料来源：[README.md:1-40]()

整体数据流可概括为：语料 → 分词器（可选 stemmer + stopwords） → 词项 ID 化 → 预计算 BM25 稀疏矩阵 → 持久化到磁盘或上传 Hub → 查询时按 query token 切片并通过 Numba 后端做 top-k 选择。下图展示了端到端的构建与查询数据流。

```mermaid
flowchart LR
    A[原始语料] --> B[Tokenizer<br/>stemmer + stopwords]
    B --> C[Token IDs / vocab]
    C --> D[BM25.index<br/>构建 CSC 稀疏矩阵]
    D --> E[save / save_vocab<br/>落盘为 npz + json]
    E --> F[(本地或 HF Hub)]
    F --> G[BM25.load / BM25HF.load_from_hub]
    G --> H[Numba 后端<br/>top-k 评分与排序]
    H --> I[(doc_ids, scores)]
```

## Numba 后端

### 选型与默认值

`bm25s` 在评分阶段默认采用 `backend="numba"`，其内部模块位于 `bm25s/numba/`，包含 `__init__.py`、`retrieve_utils.py` 与 `selection.py` 三个核心文件，分别负责 JIT 函数的导出、检索辅助计算以及 top-k 选择算法。高级 API `BM25Search` 进一步把默认参数固定为 `backend="numba", csc_backend="numpy", auto_compile=False`，确保开箱即用且无显式编译副作用。资料来源：[bm25s/high_level/__init__.py:13-40]()

### 典型用法

`examples/index_and_retrieve_with_numba.py` 给出了显式启用 Numba 后端的最小示例：

```python
import bm25s
from bm25s.tokenization import Tokenizer

retriever = bm25s.BM25(corpus=corpus, backend="numba")
retriever.index(corpus_tokens, show_progress=True)

queries_tokens = tokenizer.tokenize(queries, update_vocab=False)
results, scores = retriever.retrieve(queries_tokens, k=5)
```

`BM25.retrieve` 接受 `n_threads`、`chunksize`、`backend_selection` 等参数，控制批处理并行度与 Numba 函数的自动选择策略。当 `backend_selection="auto"` 时，库会根据查询规模在 Numba 与纯 Scipy 实现之间自动选择。资料来源：[bm25s/__init__.py:170-220]()

### 评分函数变体

`bm25s.scoring` 模块实现了多种 BM25 变体的预计算函数（Robertson、ATIRE、BM25L、BM25+、Lucene），并由 Numba 后端在查询时按所选 `method` 调用对应的 IDTF / TF 归一化逻辑。这意味着用户切换评分变体时不会丧失 Numba 加速收益。资料来源：[README.md:120-180]() 与 [bm25s/scoring.py:1-60]()

## 内存映射与索引持久化

### 落盘格式

索引并非保存原始语料，而是保存重建评分所需的稀疏矩阵与词表。`examples/save_and_reload_end_to_end.py` 展示了标准流程：

```python
retriever.save("bm25s_index_readme")
tokenizer.save_vocab(save_dir="bm25s_index_readme")

# 重新加载
reloaded_retriever = bm25s.BM25.load("bm25s_index_readme", load_corpus=True)
reloaded_tokenizer.load_vocab("bm25s_index_readme")
```

由于评分数据采用 Scipy CSC 稀疏矩阵，`save` 调用底层使用 `numpy.savez` 系列接口写出 `.npz`，词表与 stopwords 以 JSON 序列化；该格式既支持小语料的快速加载，也天然兼容 `numpy.load(..., mmap_mode="r")` 这类内存映射读取模式，从而对超出 RAM 的索引也能以惰性方式打开。资料来源：[examples/save_and_reload_end_to_end.py:1-60]() 与 [bm25s/__init__.py:170-220]()

### 批量检索与分块

对百万级文档的检索，`retrieve` 会按 `chunksize`（默认 50）将查询分块处理，从而控制中间矩阵乘法的内存峰值。结合 Numba 后端，这一组合使得 Natural Questions 等 200 万文档量级的语料可在单机单线程上完成吞吐要求。资料来源：[bm25s/__init__.py:170-220]() 与 [examples/index_nq.py]()（README 引用）

## Hugging Face 集成

### 拉取与推送索引

`bm25s.hf` 模块通过 `BM25HF` 类把本地 `save` / `load` 流程扩展到 Hugging Face Hub。核心 API 为：

| 方法 | 作用 | 关键参数 |
|------|------|----------|
| `BM25HF.load_from_hub` | 从 Hub 仓库快照下载并构建对象 | `repo_id`, `revision`, `token`, `local_dir`, `allow_pickle` |
| `save_to_hub` | 把当前索引推送到 Hub | `repo_id`, `token`, `commit_message`, `private` |
| `save_stopwords_to_hub` | 单独上传分词器停用词 | `repo_id`, `commit_message="Update stopwords"` |

`load_from_hub` 内部通过 `HfApi.snapshot_download` 获取仓库快照，再复用本地 `load_vocab` 路径重建对象，因此远程与本地格式保持一致。资料来源：[bm25s/hf.py:1-120]()

### 安装与依赖

HF 集成仅在使用时引入 `huggingface_hub`：

```bash
pip install "bm25s[full]"        # 含 PyStemmer 等可选加速
pip install huggingface_hub      # 启用 HF 集成
```

`setup.py` 中通过 `extras_require` 暴露完整可选依赖组，避免强制安装增加启动开销。资料来源：[setup.py:1-40]() 与 [README.md:60-100]()

### 端到端示例

```python
import bm25s
from bm25s.hf import BM25HF

# 加载远程索引
retriever = BM25HF.load_from_hub("username/bm25s-index")

# 用 bm25s 内置分词器做 query 编码
query_tokens = bm25s.tokenize("a cat is a feline")
results, scores = retriever.retrieve(query_tokens, k=3)
```

### 已知兼容性问题

社区曾反馈 Windows 平台下导入 `bm25s` 时，`bm25s/utils/benchmark.py` 会向 stdout 输出 `logger.warning("resource module not available on Windows")`，干扰 MCP 服务的健康检查（Issue #186、#178）。0.3.9 版本已将该日志级别降级为 `debug`（PR #187），因此在启用 HF 集成并以 MCP 方式暴露检索服务时，建议固定到 ≥0.3.9。资料来源：[bm25s/utils/benchmark.py:1-20]() 与社区上下文（Issue #186 / #178 / PR #187）。

## See Also

- [项目主页 README](https://github.com/xhluca/bm25s) — 安装、快速开始与 CLI 概览
- [高分层 API `bm25s/high_level`](https://github.com/xhluca/bm25s/blob/main/bm25s/high_level/README.md) — 1 行检索封装
- [技术报告](https://arxiv.org/abs/2407.03618) — 性能基准与稀疏矩阵设计
- [Hugging Face 博客](https://huggingface.co/blog/xhluca/bm25s) — 与主流 BM25 实现的对比
- [Issue #158](https://github.com/xhluca/bm25s/issues/158) — 关于语料格式与 API 文档的讨论

---

<a id='page-4'></a>

## CLI、High-Level API、MCP 服务器、持久化与已知问题

### 相关页面

相关主题：[项目概览、安装与快速开始](#page-1), [性能优化：Numba 后端、内存映射与 Hugging Face 集成](#page-3)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/xhluca/bm25s/blob/main/README.md)
- [bm25s/high_level/README.md](https://github.com/xhluca/bm25s/blob/main/bm25s/high_level/README.md)
- [bm25s/high_level/__init__.py](https://github.com/xhluca/bm25s/blob/main/bm25s/high_level/__init__.py)
- [bm25s/terminal/__init__.py](https://github.com/xhluca/bm25s/blob/main/bm25s/terminal/__init__.py)
- [setup.py](https://github.com/xhluca/bm25s/blob/main/setup.py)
- [bm25s/__init__.py](https://github.com/xhluca/bm25s/blob/main/bm25s/__init__.py)
- [bm25s/hf.py](https://github.com/xhluca/bm25s/blob/main/bm25s/hf.py)
- [bm25s/scoring.py](https://github.com/xhluca/bm25s/blob/main/bm25s/scoring.py)
- [examples/save_and_reload_end_to_end.py](https://github.com/xhluca/bm25s/blob/main/examples/save_and_reload_end_to_end.py)
- [examples/index_nq.py](https://github.com/xhluca/bm25s/blob/main/examples/index_nq.py)
</details>

# CLI、High-Level API、MCP 服务器、持久化与已知问题

`bm25s` 在核心 BM25 评分算法之外，提供了三类面向工程实践的"门面"组件：命令行界面（CLI）、高级 Python API（`bm25s.high_level`），以及面向 LLM 代理的 MCP（Model Context Protocol）服务器。本页汇总这些组件的设计要点、用法以及社区已知问题，并结合持久化（save/load）流程说明数据流。

## 一、命令行接口（CLI）

`bm25s` 通过 [setup.py](https://github.com/xhluca/bm25s/blob/main/setup.py) 注册了一个名为 `bm25` 的 console_script 入口：

```python
entry_points={
    "console_scripts": [
        "bm25=bm25s.cli:main",
    ],
},
```

实现位于 [bm25s/terminal/__init__.py](https://github.com/xhluca/bm25s/blob/main/bm25s/terminal/__init__.py)，主要能力包括：

| 子命令 | 功能 | 关键参数 |
| --- | --- | --- |
| `bm25 index <file>` | 从 CSV / TXT / JSON / JSONL 构建索引 | `-o` 输出目录，`-u` 写入 `~/.bm25s/indices/` |
| `bm25 search -i <index> "<query>"` | 在已有索引上查询 | `-k` top-k，`-u` 启动交互式索引选择 |
| `bm25 mcp launch` | 启动 MCP 服务器 | `--port`、`--index-dir` |

CLI 默认将索引写入用户目录 `~/.bm25s/indices/`，函数 `get_user_indices_dir()` 与 `list_user_indices()` 负责目录枚举，交互式选择依赖 `rich` 库（通过 `bm25s[cli]` extras 安装）。资料来源：[bm25s/terminal/__init__.py:get_user_indices_dir()]()、[bm25s/terminal/__init__.py:list_user_indices()]()。

## 二、High-Level API（`bm25s.high_level`）

`bm25s.high_level` 为追求"一行完成检索"的用户设计，封装了分词、停用词、词干提取与索引构建全流程。资料来源：[bm25s/high_level/README.md]()。

### 核心入口：`BM25Search`

`BM25Search` 构造函数接受语料、语种、`bm25_kwargs` 与 `tokenizer_kwargs`，并在内部启用 numba 后端与英文词干提取。资料来源：[bm25s/high_level/__init__.py:BM25Search.__init__()]()：

```python
bm25_kwargs_default = dict(
    backend="numba", csc_backend="numpy", auto_compile=False
)
tokenizer_kwargs_default = dict(
    stemmer=stemmer, stopwords="english", lower=True
)
```

注意：当前实现仅支持 `language="english"`，传入其他语言会抛出 `NotImplementedError`。

### 文件加载：`load()`

`load(path, document_column=None)` 支持四种格式：`.txt`、`.json`、`.jsonl`、`.csv`。当 JSON 数据为字典列表时，必须显式指定 `document_column`，否则默认取第一个键。资料来源：[bm25s/high_level/__init__.py:load()]()。这一行为也对应社区议题 #158 中"语料格式歧义"的反馈——用户常误以为可以省略列名。

### 一键检索示例

```python
import bm25s.high_level as bm25

corpus = bm25.load("documents.csv", document_column="text")
retriever = bm25.index(corpus)
results = retriever.search(["how to learn python"], k=5)
```

`BM25` 检索接口 `retrieve` 接受 `corpus` 参数，用于在返回时以原始文档（字符串、字典或外部 ID）替代内部 ID，便于业务直接消费。资料来源：[bm25s/__init__.py:BM25.retrieve()]()。

## 三、MCP 服务器

`bm25s` 内置了 Model Context Protocol 服务器，使 LLM 代理能够把 BM25 索引当作工具调用。安装命令：

```bash
uv pip install "bm25s[mcp]"
```

启动命令形如：

```bash
bm25 mcp launch --port 8000 --index-dir ./bm25s_indices/nq
```

服务器读取由 `retriever.save(index_dir)` 与 `tokenizer.save_vocab(index_dir)` 共同产出的索引目录，从而对外暴露 `retrieve(query, k)` 工具。资料来源：[examples/index_nq.py]()、[README.md]()。

## 四、持久化与数据流

下图描述从语料到可重加载索引的完整数据流：

```mermaid
flowchart LR
    A[原始语料<br/>list of str/dict] --> B[Tokenizer.tokenize<br/>return_as='tuple']
    B --> C[BM25.index<br/>构建稀疏矩阵]
    C --> D[retriever.save<br/>保存参数与矩阵]
    C --> E[tokenizer.save_vocab<br/>保存词表]
    D --> F[index_dir]
    E --> F
    F --> G[BM25.load<br/>+ tokenizer.load_vocab]
    G --> H[retrieve 查询]
```

关键点：

1. `retriever.save(index_dir)` 会生成 `params.index.json` 等元数据文件（CLI 借此识别有效索引）。资料来源：[bm25s/terminal/__init__.py:list_user_indices()]()。
2. `tokenizer.save_vocab()` 必须与 `save_stopwords()` 配套保存，否则重载后查询会因词表缺失而失败。
3. 评分核心使用稀疏矩阵与 NumPy 后端；`scoring.py` 中的 `_build_idf_array`、`_build_nonoccurrence_array` 负责提前计算所有 token 的 IDF 与非出现惩罚。资料来源：[bm25s/scoring.py]()。
4. Hugging Face Hub 集成见 [bm25s/hf.py]()，通过 `BM25HF.load_from_hub` 拉取已发布索引。

## 五、社区已知问题

### Windows 上的 `resource module not available` 警告

在 Windows 平台，`bm25s.utils.benchmark` 在导入时尝试加载 Unix 专有的 `resource` 模块失败，并在 0.3.8 及更早版本中通过 `logger.warning` 输出 `"resource module not available on Windows"`，破坏了 MCP 健康检查与 stdout 整洁性。社区议题 #178、#186 对此提出了报告。

修复：0.3.9 版本将日志级别从 `warning` 下调为 `debug`（PR #187），相关变更已合并。资料来源：[README.md（Latest Release: 0.3.9）]()。

### 语料格式歧义（#158）

文档曾在不同位置描述 `corpus` 既可为字符串列表，也可为字典列表，造成 API 解读不一致。`bm25s.high_level.load()` 在 JSON 字典场景下需要显式 `document_column`，这是当前最权威的格式契约。资料来源：[bm25s/high_level/__init__.py:load()]()。

### 致谢请求（#80）

社区提议在 README 中致谢 `bm25_pt`，因为评分机制与 API 设计与之高度相似。这一请求体现了 bm25 生态的血缘关系。

## See Also

- [核心 BM25 评分与变体（Robertson、ATIRE、BM25L、BM25+、Lucene）](README.md)
- [分词器与词干提取（PyStemmer）](bm25s/high_level/README.md)
- [Hugging Face Hub 索引发布](bm25s/hf.py)
- [Memory-mapped 检索与大批量处理](examples/index_nq.py)

---

<!-- evidence_pipeline_checked: true -->
<!-- evidence_injected: true -->

---

## Doramagic 踩坑日志

项目：xhluca/bm25s

摘要：发现 11 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：安装坑 - 来源证据：Version mismatch in version.py: Recommend adaptive version strategy。

## 1. 安装坑 · 来源证据：Version mismatch in version.py: Recommend adaptive version strategy

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：Version mismatch in version.py: Recommend adaptive version strategy
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/xhluca/bm25s/issues/184 | 来源讨论提到 python 相关条件，需在安装/试用前复核。

## 2. 安装坑 · 来源证据：`resource module not available on Windows` printed to stdout

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：`resource module not available on Windows` printed to stdout
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/xhluca/bm25s/issues/178 | 来源讨论提到 python 相关条件，需在安装/试用前复核。

## 3. 安装坑 · 来源证据：jax import guard should also check for `RuntimeError`

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：jax import guard should also check for `RuntimeError`
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/xhluca/bm25s/issues/173 | 来源类型 github_issue 暴露的待验证使用条件。

## 4. 配置坑 · 来源证据：logger.warning on every import breaks MCP health checks on Windows

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个配置相关的待验证问题：logger.warning on every import breaks MCP health checks on Windows
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/xhluca/bm25s/issues/186 | 来源讨论提到 python 相关条件，需在安装/试用前复核。

## 5. 能力坑 · 能力判断依赖假设

- 严重度：medium
- 证据强度：source_linked
- 发现：README/documentation is current enough for a first validation pass.
- 对用户的影响：假设不成立时，用户拿不到承诺的能力。
- 证据：capability.assumptions | https://github.com/xhluca/bm25s | README/documentation is current enough for a first validation pass.

## 6. 运行坑 · 来源证据：Format of corpus and API reference

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个运行相关的待验证问题：Format of corpus and API reference
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/xhluca/bm25s/issues/158 | 来源类型 github_issue 暴露的待验证使用条件。

## 7. 维护坑 · 维护活跃度未知

- 严重度：medium
- 证据强度：source_linked
- 发现：未记录 last_activity_observed。
- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。
- 证据：evidence.maintainer_signals | https://github.com/xhluca/bm25s | last_activity_observed missing

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 证据：downstream_validation.risk_items | https://github.com/xhluca/bm25s | no_demo; severity=medium

## 9. 安全/权限坑 · 存在评分风险

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：风险会影响是否适合普通用户安装。
- 证据：risks.scoring_risks | https://github.com/xhluca/bm25s | no_demo; severity=medium

## 10. 维护坑 · issue/PR 响应质量未知

- 严重度：low
- 证据强度：source_linked
- 发现：issue_or_pr_quality=unknown。
- 对用户的影响：用户无法判断遇到问题后是否有人维护。
- 证据：evidence.maintainer_signals | https://github.com/xhluca/bm25s | issue_or_pr_quality=unknown

## 11. 维护坑 · 发布节奏不明确

- 严重度：low
- 证据强度：source_linked
- 发现：release_recency=unknown。
- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。
- 证据：evidence.maintainer_signals | https://github.com/xhluca/bm25s | release_recency=unknown

<!-- canonical_name: xhluca/bm25s; human_manual_source: deepwiki_human_wiki -->
