了解 pg_bestmatch 如何将 BM25 排序转化为稀疏向量内积,以及通过预编译包或源码安装并启用扩展。
这是本节的多页打印视图。 .
pg_bestmatch 文档
- 1: 安装与工作原理
- 2: 使用指南
- 3: SQL 参考与方案对比
pg_bestmatch(pg_bestmatch.rs)是一个基于 Rust(pgrx)开发的 PostgreSQL 扩展,它通过将文档与查询文本转化为兼容 pgvector(sparsevec)与 pgvecto.rs(svector)的 BM25 加权稀疏向量,在 PostgreSQL 内部原生实现 Okapi BM25 全文相关性排序。
vchord_bm25 + pg_tokenizerpg_bestmatch.rs 是 TensorChord 第一代基于稀疏向量内积的 BM25 检索方案。对于新建生产环境,我们推荐使用新一代 vchord_bm25 搭配 pg_tokenizer——它采用专门设计的 Block-WeakAnd(WAND) 倒排索引替代了稀疏向量 HNSW 近似图检索,支持 100% 精确的 Top-K BM25 计分与更高吞吐量。
核心能力
- 数据库内原生生成 BM25 稀疏向量:在
bm25_catalog模式中维护语料库词频(TF)、逆文档频率(IDF)与平均文档长度统计信息,直接为文档与查询生成 BM25 稀疏向量。 - 无缝对接
pgvector与pgvecto.rs:支持直接输出标准sparsevec(pgvector 0.7.0+)或svector(pgvecto.rs),使用负内积操作符<#>即可计算 BM25 得分并利用 HNSW 索引加速。 - 内置分词器:内置 HuggingFace
bert-base-uncasedWordPiece 词表(30,522维),并提供独立的tokenize(text)SQL 分词函数。
文档章节导航
基于斯坦福 LoCo 基准数据集的端到端实战教程,演示结合 pgvector sparsevec 与 pgvecto.rs svector 的完整检索流程。
bm25_create、bm25_refresh、bm25_drop、bm25_document_to_svector、bm25_query_to_svector 与 tokenize 完整参考及方案对比。
1 - 安装与工作原理
pg_bestmatch 工作原理
给定文档 与分词为词元序列 的查询 ,标准的 Okapi BM25 相关性得分公式为:
可以看到,上述求和本质上是词表空间 (内置 bert-base-uncased 词表维度为 )中两个稀疏向量的内积(Dot Product):
- 文档稀疏向量 :对于文档 中出现的每个词元 ,在对应维度存储经文档长度归一化的词频(TF)权重:
- 查询稀疏向量 :对于查询 中的每个词元 ,在对应维度存储其逆文档频率权重 。
当使用 pgvector 或 pgvecto.rs 的负内积操作符 <#> 计算 与 的距离时,PostgreSQL 会返回 。因此,执行 ORDER BY embedding <#> query_vec ASC 即可按 BM25 相关性从高到低返回最匹配的文档!
安装扩展
前置依赖
请先安装 pgvector(需 v0.7.0+ 以支持 sparsevec 类型)或 pgvecto.rs(需 v0.3.0+ 以支持 svector 类型)。
通过预编译包安装(Debian / Ubuntu)
从 GitHub Releases 下载对应 PostgreSQL 大版本的 .deb 安装包:
从源码编译安装(cargo pgrx)
确保系统已安装 Rust 工具链与 cargo-pgrx:
启用扩展
连接到 PostgreSQL,创建扩展并将 bm25_catalog 加入 search_path:
执行一条 SQL 验证内置分词器:
接下来请阅读使用指南,了解端到端的 BM25 稀疏向量建表、建索引与检索流程。
2 - 使用指南
本指南演示如何将 pg_bestmatch 与 pgvector(sparsevec)搭配完成端到端的 BM25 文本检索流程,并附带基于 pgvecto.rs(svector)的等效用法。
1. 启用扩展并设置 search_path
2. 创建文档表并写入测试数据
3. 创建 BM25 语料库统计集
调用 bm25_create(table_name, column_name, statistic_name, b, k) 为目标表与文本列创建 BM25 统计信息(b = 0.75、k = 1.2 为默认推荐参数):
bm25_create 会在后台执行以下操作:
- 在
bm25_catalog模式下创建统计表与物化视图,统计全局词频、文档频率及文档总数。 - 在
documents表上注册触发器,自动追踪后续新增或删除的记录。
当向表中大批量写入新文档后,如果希望重新计算全局逆文档频率(IDF)与平均文档长度(avgdl),请执行:
4. 生成文档稀疏向量列(配合 pgvector)
为 documents 表添加 sparsevec(30522) 列,并调用 bm25_document_to_svector 生成文档向量:
5. 创建 HNSW 稀疏向量索引
使用 pgvector 的 HNSW 索引与内积操作符类 sparsevec_ip_ops:
6. 执行 BM25 检索查询
使用 bm25_query_to_svector 将查询词转化为稀疏向量,并按 <#>(负内积)升序排序:
配合 pgvecto.rs(svector)使用
如果您使用的是 pgvecto.rs(v0.3.0+),可省略 'pgvector' 参数(或显式传入 'pgvecto.rs')并将返回值转换为 svector:
3 - SQL 参考与方案对比
SQL 函数参考(bm25_catalog)
pg_bestmatch 的所有 SQL 函数均位于 bm25_catalog 模式下。
bm25_create
为指定的表与文本列创建 BM25 语料库统计信息。
table_name:包含文档数据的目标表名。column_name:待分析的text文本列名。statistic_name:该 BM25 统计集的唯一标识名称(需为合法的 SQL 标识符)。b:BM25 文档长度归一化系数(默认0.75)。k:BM25 词频饱和度参数 (默认1.2)。
bm25_refresh
在文档发生增删改后,刷新 statistic_name 对应的物化语料库统计数据。
bm25_drop
删除与 statistic_name 关联的所有内部统计表、物化视图与触发器。
bm25_document_to_svector
将文档字符串转化为兼容 pgvecto.rs(svector)或 pgvector(sparsevec)的 BM25 词频权重稀疏向量字面量(text)。
statistic_name:已注册的统计集名称。passage:输入文档文本。style:输出格式——'pgvector'(下标从 1 开始)或'pgvecto.rs'(下标从 0 开始)。
bm25_query_to_svector
将检索查询字符串转化为带 IDF 权重的稀疏向量字面量(text)。
tokenize
使用内置的 bert-base-uncased WordPiece 词表,将输入字符串切分为子词词元数组(text[])。
方案对比:pg_bestmatch vs vchord_bm25
pg_bestmatch 与 vchord_bm25 均由 TensorChord 团队开发,旨在将 Okapi BM25 排序引入 PostgreSQL,但两者采用了截然不同的底层架构:
| 对比维度 | pg_bestmatch(pg_bestmatch.rs) |
vchord_bm25 + pg_tokenizer |
|---|---|---|
| 核心机制 | 将 BM25 的 TF/IDF 权重映射为稀疏向量(sparsevec / svector) |
原生倒排索引 + Block-WeakAnd(WAND) 块级剪枝扫描 |
| 索引类型 | 复用 pgvector 或 pgvecto.rs 的 HNSW 稀疏向量索引 |
专用 USING bm25 (vec bm25_ops) 索引访问方法 |
| 检索精度 | 近似检索(基于稀疏向量 HNSW 图遍历) | 100% 精确 Top-K BM25 计分 |
| 分词能力 | 固定内置 bert-base-uncased 词表(30,522 维) |
可插拔 pg_tokenizer(支持 Unicode、Jieba、Lindera、HuggingFace、Snowball 及自定义语料词表) |
| 适用场景 | 仅安装了 pgvector 环境下的轻量级实验与基准对比 |
生产级全文检索与多路混合检索首选 |