教学型稀疏向量检索引擎


文档摘要

源文件:chapter3/sparse-embedding/README.md 教学型稀疏向量检索引擎 一个基于倒排索引和 BM25 算法的稀疏向量检索引擎教学实现。本项目通过详尽的日志与可视化特性,展示信息检索的基础概念。 特性 完整的 BM25 实现:完整实现 BM25 排序算法 高级分词:全面处理数字、代码、技术术语和混合大小写的分词器 倒排索引:用于词项查找的高效倒排索引数据结构 HTTP API:基于 FastAPI 构建的 RESTful API 交互式 Web UI:浏览器端的索引与检索界面 详尽日志:贯穿索引与检索全过程的详细教学日志 索引可视化:检查索引内部结构的 API 内存存储:为教学目的采用的简单内存存储 分词能力 TextProcessor

源文件:chapter3/sparse-embedding/README.md

教学型稀疏向量检索引擎

一个基于倒排索引和 BM25 算法的稀疏向量检索引擎教学实现。本项目通过详尽的日志与可视化特性,展示信息检索的基础概念。

特性

  • 完整的 BM25 实现:完整实现 BM25 排序算法
  • 高级分词:全面处理数字、代码、技术术语和混合大小写的分词器
  • 倒排索引:用于词项查找的高效倒排索引数据结构
  • HTTP API:基于 FastAPI 构建的 RESTful API
  • 交互式 Web UI:浏览器端的索引与检索界面
  • 详尽日志:贯穿索引与检索全过程的详细教学日志
  • 索引可视化:检查索引内部结构的 API
  • 内存存储:为教学目的采用的简单内存存储

分词能力

TextProcessor 现在为真实文本提供全面的分词:

  • 数字4043.142.0.1
  • 代码XK9-2B4-7Q1API_KEY_123
  • 技术术语C++.NETNode.js
  • 混合大小写JavaScriptPyTorchiPhone
  • 邮箱user@example.com
  • 十六进制代码#FF57330x1234
  • 缩略语APIHTTPNASA
  • 字母数字混合Python3ES6HTML5

架构

核心组件

  1. TextProcessor:处理单词、数字、代码、技术术语和混合大小写的高级分词器
  2. InvertedIndex:维护带有词频和文档频率的倒排索引结构
  3. BM25:实现用于相关性打分的 BM25 排序算法
  4. SparseSearchEngine:协调所有组件的主引擎
  5. HTTP Server:基于 FastAPI 的服务,暴露检索引擎功能

BM25 算法

BM25(Best Matching 25)是一种概率排序函数,根据查询词项为文档打分。该算法使用:

  • 词频(TF):某词项在文档中出现的频次
  • 逆文档频率(IDF):某词项在所有文档中是稀有还是常见
  • 文档长度归一化:根据文档长度调整分数

关键参数:

  • k1(默认 1.5):控制词频饱和
  • b(默认 0.75):控制长度归一化

安装

  1. 安装依赖:
pip install -r requirements.txt

cli.py(下节的命令行工具)只依赖 Python 标准库,无需安装任何第三方包即可离线运行;server.py / demo.py 才需要上面的 FastAPI 等依赖。

命令行工具 cli.py(实验 3-5,推荐入口)

cli.py 提供一个完全离线的命令行入口:在一个内置的 10 篇小型语料上运行 BM25 稀疏检索、复现书中“逐词 IDF/TF/BM25 贡献”的日志,并在带标注的评测集上计算 recall/precision/MRR。所有参数都有中文 --help

python cli.py --help # 查看全部参数(中文) python cli.py # 默认演示:查询 "model distillation" python cli.py -q "model distillation" --explain # 逐词展示 TF/IDF/BM25 贡献(对应书中日志) python cli.py --eval # 在标注集上计算 recall@k / precision@k / MRR python cli.py -q "cat" # 观察 BM25 读不懂同义词的短板(kitten/feline 漏召回) python cli.py --corpus my.json -q "查询" -o out.json # 自定义语料 + 结果落盘 python cli.py --k1 2.0 -b 0.5 -q "..." # 调 BM25 参数 k1 / b python cli.py --method splade -q "..." # 学习型稀疏检索 SPLADE(需预先下载模型)

主要参数:

参数 说明
-q, --query 查询字符串(默认 model distillation
-c, --corpus 语料文件(.json 文档数组或 .jsonl 每行一篇);缺省用内置示例语料
-m, --method bm25(默认,离线)或 splade(学习型稀疏,需下载模型)
-k, --top-k 返回前 k 条(默认 5)
-o, --output 把结果 / 评测指标写入 JSON 文件
--eval 在标注集上评测 recall@k / precision@k / MRR
--labels 自定义评测标注 {query: [相关doc_id,...]}
--explain 对命中文档逐词展示 TF / IDF / BM25 贡献
--k1 / -b BM25 词频饱和参数 k1、文档长度归一化参数 b
-v, --verbose 打开引擎 DEBUG 日志(分词、倒排索引构建、打分全过程)

检索质量评测(--eval)

内置标注集覆盖精确关键词、错误码、专有名称与“只有同义表达”的查询。python cli.py --eval 的真实输出(k=5):

查询 'model distillation' recall@5=1.00 precision@5=1.00 RR=1.00 查询 'HTTP 404 error' recall@5=1.00 precision@5=0.50 RR=1.00 查询 'XK9-2B4-7Q1' recall@5=1.00 precision@5=1.00 RR=1.00 查询 'BM25 ranking function' recall@5=1.00 precision@5=1.00 RR=1.00 查询 'cat' recall@5=0.00 precision@5=0.00 RR=0.00 <- 漏召回(同义词短板) 宏平均 recall@5=0.800 precision@5=0.700 MRR=0.800 漏召回率(1-recall@5)=0.200

结果直观印证了书中的结论:BM25 在精确关键词、错误码、专有名称上表现极佳(recall=1.0),但读不懂同义词——查询 cat 无法命中只写了 kitten / feline 的文档(recall=0)。这一长一短正是引入混合检索(见实验 3-6 retrieval-pipeline)的动机。

学习型稀疏检索(--method splade)

--method splade 对应书中提到的学习型稀疏检索(SPLADE):用掩码语言模型为每个词项打权重,并能为原文未出现但语义相关的词项补权重(术语扩展)。它需要下载预训练模型 naver/splade-cocondenser-ensembledistil(依赖 torchtransformers)。离线环境下无法下载权重时,命令会快速给出清晰提示(并说明 BM25 路径无需任何模型即可离线运行),不会卡在网络下载上。联网环境可先执行 huggingface-cli download naver/splade-cocondenser-ensembledistil 缓存模型后再运行。

用法

启动服务

python server.py

服务会在 http://localhost:4241 启动。

Web 界面

打开浏览器访问 http://localhost:4241 即可使用交互式 Web UI。

API 端点

索引文档

POST /index { "text": "Your document text here", "metadata": {"title": "Document Title", "category": "Category"} }

检索文档

POST /search { "query": "your search query", "top_k": 10 }

获取统计

GET /stats

获取索引结构

GET /index/structure

按 ID 取回文档

GET /document/{doc_id}

清空索引

DELETE /index

运行演示

python demo.py

演示脚本会:

  1. 清空已有索引
  2. 索引关于编程和计算机科学的示例文档
  3. 显示索引统计
  4. 展示内部索引结构
  5. 执行多种检索查询
  6. 演示文档取回

教学特性

详尽日志

系统在每一步都提供详细日志:

  • 文档分词过程
  • 词频计算
  • IDF 分数计算
  • 每个词项的 BM25 打分
  • 查询处理步骤
  • 候选文档识别

索引可视化

/index/structure 端点返回:

  • 倒排索引映射(词项到文档)
  • 文档统计(长度、唯一词项、高频词项)
  • BM25 参数
  • 全局词频分布

检索结果中的调试信息

每条检索结果都包含调试信息:

  • 匹配到的查询词项
  • 文档长度
  • 查询词项的词频
  • 各词项对最终分数的贡献

示例输出

索引日志

2024-01-15 10:30:45 - Indexing document with ID 0 2024-01-15 10:30:45 - Document text: Python is a high-level programming... 2024-01-15 10:30:45 - Tokenizing text of length 142 2024-01-15 10:30:45 - Found 23 raw tokens 2024-01-15 10:30:45 - After removing stop words: 15 tokens 2024-01-15 10:30:45 - Document 0: 15 tokens, 12 unique terms 2024-01-15 10:30:45 - Document 0 indexed successfully

检索日志

2024-01-15 10:31:20 - Searching for: 'machine learning algorithms' 2024-01-15 10:31:20 - Query terms after processing: ['machine', 'learning', 'algorithms'] 2024-01-15 10:31:20 - Term 'machine' appears in 2 documents 2024-01-15 10:31:20 - Term 'learning' appears in 3 documents 2024-01-15 10:31:20 - Term 'algorithms' appears in 1 document 2024-01-15 10:31:20 - Found 4 candidate documents 2024-01-15 10:31:20 - IDF for 'machine': N=10, df=2, idf=1.7918 2024-01-15 10:31:20 - Term 'machine' in doc 1: tf=2, dl=35, score=3.2451 2024-01-15 10:31:20 - Document 1 total score: 7.8923 2024-01-15 10:31:20 - Returning top 3 results

API 文档

服务运行时,可在 http://localhost:4241/docs 访问交互式 API 文档。

项目结构

sparse-embedding/ ├── bm25_engine.py # 核心检索引擎实现 ├── cli.py # 离线 argparse CLI:BM25/SPLADE 检索 + recall/precision 评测 ├── server.py # FastAPI HTTP 服务 ├── demo.py # 演示脚本 ├── requirements.txt # Python 依赖 └── README.md # 本文件

学习资源

本实现演示了:

  • 搜索引擎中倒排索引的工作原理
  • BM25 排序背后的数学原理
  • 词频与文档频率概念
  • 文本预处理的重要性
  • 稀疏向量如何表示文档
  • 检索系统的 RESTful API 设计

局限性

这是一个教学实现,存在一些局限:

  • 内存存储(不持久化)
  • 基础分词(可通过词形归一改善)
  • 仅支持英文停用词
  • 不支持短语查询
  • 无查询扩展或同义词
  • 单线程处理

改进方向

潜在的学习向增强:

  • 用数据库添加持久化
  • 实现更高级的文本处理(词干提取、词形归一)
  • 增加短语查询支持
  • 实现查询扩展
  • 增加多语言支持
  • 实现索引压缩技术
  • 增加按字段检索支持
  • 实现更多排序算法(TF-IDF、Okapi BM25+)

作者与出处
原作者: bojieli
来源:bojieli
许可证:Apache-2.0
整理: 灏天文库整理
由灏天文库结构化整理,提供目录导航、全文检索与在线阅读,便于系统化学习
发布者: 作者: bojieli 转发
评论区 (0)
U