读书笔记 · 约 12,038 字 · 预计推送 2 部分

全文检索工程:BM25、FTS5、倒排索引、向量检索与混合检索 :: 解释个人知识库如何组合 未开始

目录

题记与说明

精读日期:2026-11-01 | 主题编号:knowledge-4okgaw4b-1 | 类型:主题研究(6 个在线来源逐字精读 + 1 次本地实验验证 + 1 组检索级补充)
笔记路径:D:/CodexData/nightshift/output/knowledge/notes/2026-11-01-knowledge-4okgaw4b-1-全文检索工程-BM25-FTS5-倒排索引-向量检索与混合检索-精读笔记.md

一、来源清单与阅读状态

#来源类型阅读深度状态
1SQLite FTS5 Extension 官方文档官方文档全文要点逐节提取,含原文引述✅ 精读
2Elastic: Practical BM25 Part 2 — the BM25 Algorithm and its Variables技术博客公式逐变量解释,含原文引述✅ 精读
3Anthropic: Introducing Contextual Retrieval厂商技术博客实验数字与管线逐条提取✅ 精读
4Weaviate: Hybrid Search Explained向量库官方博客融合算法与参数提取✅ 精读
5Elasticsearch 文档: Reciprocal Rank Fusion官方文档公式与参数逐条提取✅ 精读
6arXiv 2104.08663: BEIR (NeurIPS 2021)论文摘要页摘要与结论提取(原文因引用上限未逐字复制)✅ 精读
7中文分词方案(wangfenjin/simple、trigram 路线等)检索结果汇总仅检索级阅读,未逐字精读原页⚠️ 检索级
—Wikipedia: BM25(Robertson & Zaragoza 原始综述亦未获取)——❌ 连接超时,未读成

本地验证:Windows + Python 3 + sqlite 3.50.4,运行 PYTHONIOENCODING=utf-8 python -I fts5_demo.py(脚本见工作区,内容见第三节)。


二、逐来源精读

来源 1:SQLite FTS5 官方文档(词法检索的"单机最优解")

FTS5 是 SQLite 的全文检索虚拟表模块,原文定义:

"FTS5 is an SQLite virtual table module that provides full-text search functionality to database applications."

倒排索引的实现:FTS5 不扫描原表,而是维护"词 → 文档(及位置)"的倒排结构,物理上是每个提交事务一棵 b-tree、后台定期合并:

the index is stored as "a series of b-trees"(§6.1),one b-tree per committed transaction, merged periodically.

这意味着全文检索延迟与语料总量近似无关,只与命中词表大小有关——这是个人知识库(万级以下笔记)能把搜索做到毫秒级的根本原因。

BM25 内建排序(§5.1.1):

分词器(§4.3):unicode61(默认,按 Unicode 类别切词,默认只把 L*/N*/Co 当 token 字符)、ascii、porter(英文词干化包装器)、trigram(3 字符滑窗,支持子串匹配和加速 LIKE/GLOB)。

内容管理三种模式(§4.4)——个人知识库同步问题的关键:

来源 2:Elastic《Practical BM25 Part 2》(BM25 公式的权威通俗解释)

BM25 分数 = 对每个查询词 qᵢ 求和:IDF(qᵢ) × tf 饱和项 × 长度归一项。变量含义:

一句话:BM25 = TF-IDF 的工程修正版,修正了"词频线性放大"和"长文档天然吃亏"两个原始 TF-IDF 的缺陷。

来源 3:Anthropic《Contextual Retrieval》(词法+语义组合的量化证据)

方法:给每个 chunk 用 Claude(Haiku)生成 50–100 token 的上下文前缀,再分别做 embedding(Contextual Embeddings)和建 BM25 索引(Contextual BM25);检索时两路召回、rank fusion 合并去重、可选 reranker 重排。

核心数字(top-20-chunk 检索失败率 = 1 − recall@20):

配置失败率相对基线降低
仅普通 embeddings(基线)5.7%—
Contextual Embeddings3.7%35%
Contextual Embeddings + Contextual BM252.9%49%
再加 Reranking(Cohere)1.9%67%

原文引述:

"Contextual Retrieval solves this problem by prepending chunk-specific explanatory context to each chunk."
"While embedding models excel at capturing semantic relationships, they can miss crucial exact matches."(例:查 "Error code TS-999",embedding 可能错过精确的 "TS-999",BM25 则直接找这个字符串)
"Embeddings+BM25 is better than embeddings on their own."

成本侧:prompt caching 让文档只加载一次而非每 chunk 一次,*"reducing latency by > 2x and costs by up to 90%"*;生成上下文成本约 $1.02 / 百万文档 token(按 800-token chunk、8k-token 文档估算)。重排用法:先取 top 150,reranker 打分后留 top 20 进 prompt;top-20 优于 top-10/top-5。

来源 4:Weaviate《Hybrid Search Explained》(混合检索的两种融合)

定义:混合检索把 dense(语义向量)与 sparse(BM25/关键词)召回合并,*"dense and sparse vectors together to deliver the best of both search methods"*。

来源 5:Elasticsearch 文档《Reciprocal Rank Fusion》(RRF 的准确定义)

伪代码(原文):

score = 0.0
for q in queries:
    if d in result(q):
        score += 1.0 / ( k + rank( result(q), d ) )

来源 6:BEIR(arXiv 2104.08663,NeurIPS 2021)——"BM25 仍是硬基线"的学术证据

来源 7(检索级补充):中文语料的分词坑

FTS5 默认 unicode61 按空格/标点切词,中文整句会被并成一个 term,导致句中词无法命中(此为检索结果与 wangfenjin/simple 等社区资料一致的说法,未逐字精读原页)。主流两条路:trigram(零扩展,但查询词需 ≥3 字符)与自定义分词器(jieba / wangfenjin/simple,支持拼音与高亮)。——下节用本地实验证实。


三、本地实验验证(本次实跑)

命令:PYTHONIOENCODING=utf-8 python -I fts5_demo.py(SQLite 3.50.4,内存库)。脚本与输出:

sqlite version: 3.50.4
[unicode61] MATCH '公园' (mid-sentence 2-char): []
[unicode61] MATCH whole-sentence-as-token: []
[trigram]  MATCH '去公园' (3 chars): [(1,)]
[trigram]  MATCH '公园'   (2 chars): []
[trigram]  MATCH '公园散步' (4 chars): [(1,)]
[bm25] rowid=6 score=-1.2472 body=bm25 ranking makes rare words score higher in
[bm25] rowid=2 score=-0.0000 body=sqlite fts5 provides full-text search for sql
[bm25] rowid=4 score=-0.0000 body=sqlite supports many platforms
[bm25] rowid=1 score=-0.0000 body=sqlite is a small fast reliable database engi
[contentless] UPDATE failed as documented: cannot UPDATE contentless fts5 table: t4

逐条解读:

  1. unicode61 对中文确实失效:文本"今天天气很好,我们一起去公园散步。"里查"公园"返回 0 行(CJK 按标点切成两个长 token,句中词无法命中);连不带标点的整串查询也 0 行(查询侧被切成了第三个形态的 token)——来源 7 的说法被实跑证实。
  2. trigram 可查中文但有 3 字符下限:"去公园"(3 字)、"公园散步"(4 字)命中;"公园"(2 字)不命中。中文高频双字词是 trigram 路线的真实盲区。
  3. bm25() 的 IDF 与符号约定:查 sqlite OR bm25,含稀有词 bm25 的文档得分 -1.2472 排第一;"sqlite" 在 6 篇中出现 4 篇,IDF 趋近 0,分数 -0.0000——证实"越稀有越该靠前"与"分数越负越好"。
  4. contentless 表确实不支持 UPDATE:报错 cannot UPDATE contentless fts5 table,与官方文档 §4.4.1 一致。

四、七维提取

1. 核心问题

个人知识库(几千~几万条笔记/文档)如何在零服务器、低成本前提下做到"既搜得到原词、又搜得到意思"?——即:BM25/倒排索引(词法精确召回)与向量检索(语义泛化召回)各自解决什么、各自在什么情况下失效、两者如何融合成一个可靠的检索层。

2. 主要主张

3. 方法(技术路线)

4. 数据与证据

5. 结论

个人知识库的组合配方收敛为一条五层管线:
① 数据层:笔记进 SQLite(或外部文件 + external-content 表),触发器同步索引;
② 词法层:FTS5 倒排索引 + bm25()(标题列加权 10×);中文语料选 trigram(零依赖、≥3 字)或 jieba/simple 分词器(双字词友好、支持拼音);
③ 语义层:chunk(数百 token)→ embedding(本地模型或 API),可选上下文前缀;
④ 融合层:RRF(k=60)合并两路 top-k,零调参;
⑤ 重排层(可选):cross-encoder 对融合后 top 150 精排出 top 20。
规模论证:万级以下语料,FTS5 毫秒级、embedding 一次性建库,单文件数据库 + 脚本即可承载,无需 Elasticsearch/独立向量库。

6. 局限

7. 对我的启发


五、一句话总结

倒排索引解决"快",BM25 解决"准"(词法侧),向量解决"懂"(语义侧),RRF 解决"合"(免调参),reranker 解决"最后一厘米";个人知识库的最优组合不是选边,而是 SQLite FTS5 + embeddings + RRF 的三层叠加——证据链:FTS5 官方文档(机制)→ Elastic(公式)→ BEIR(学术基准)→ Anthropic(组合后的量化增益)→ 本地实验(中文坑的实证)。

参考

  1. SQLite FTS5 Extension — https://sqlite.org/fts5.html
  2. Practical BM25 Part 2: the BM25 Algorithm and its Variables — https://www.elastic.co/blog/practical-bm25-part-2-the-bm25-algorithm-and-its-variables
  3. Introducing Contextual Retrieval — https://www.anthropic.com/news/contextual-retrieval
  4. Hybrid Search Explained — https://weaviate.io/blog/hybrid-search-explained
  5. Reciprocal Rank Fusion (Elasticsearch Guide) — https://www.elastic.co/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion
  6. BEIR: A Heterogeneous Benchmark for Zero-shot Evaluation of IR Models (arXiv 2104.08663, NeurIPS 2021) — https://arxiv.org/abs/2104.08663
  7. Cormack et al., SIGIR 2009, Reciprocal Rank Fusion(经来源 5 引用,原文 PDF 未直接获取)
  8. wangfenjin/simple:支持中文与拼音的 SQLite FTS5 分词扩展 — https://github.com/wangfenjin/simple (检索级)
  9. (未读成)Wikipedia: Okapi BM25 — https://en.wikipedia.org/wiki/Okapi_BM25
← 资料库今日播报 →