vchord_bm25 1.0.0:PGSTY 接手后的首个发布
vchord_bm25 1.0.0 是 PGSTY 在 pgsty/vchord_bm25 维护的首个正式版本,采用 AGPL-3.0 许可证发布。它使用 PostgreSQL 原生 tsvector 索引替代 0.3.x 的自定义 bm25vector 类型与固定 bm25_catalog 模式,重新设计了支持按需续扫与并发 VACUUM 维护的 Block-WeakAnd(WAND)存储引擎,并在索引扫描与标量评分两条路径上加入了表/列权限检查与行级安全策略(RLS)防护。
- GitHub Release:
pgsty/vchord_bm25 1.0.0· 源码仓库 - 扩展目录主页:pgext.cloud (
vchord_bm25) · Pigsty 扩展页面 (pigsty.cc) - 二进制软件包:RPM / DEB 软件源配置 · SBOM 与许可证清单
1.0.0 修改概览
| 方面 | 修改 |
|---|---|
原生 tsvector 接口 |
直接使用 USING bm25 (... bm25_ops) 为标准 PostgreSQL tsvector 列建立索引;to_bm25query(tsvector, regclass) 构造查询,<&> 返回负值 double precision BM25 分数(零分统一为 +0.0)。 |
| 可迁移模式 | 扩展对象直接安装在目标模式(默认 public),支持 ALTER EXTENSION vchord_bm25 SET SCHEMA,不再依赖固定的 bm25_catalog 模式。 |
| 可续扫的 WAND 检索 | bm25.limit 与索引 limit 选项(0..=65535,默认 100,显式设为 0 时同样取 100)作为初始 WAND top-K 批次大小而非硬性结果上限;扫描按需继续遍历后续匹配行、零分行与 NULL 行。 |
| 共享统计信息缓存 | 预处理的语料统计信息与增长段(growing)评分按 (index, query) 在 work_mem 预算内缓存,并在同一次执行的索引扫描与标量 <&> 计算之间共享(标记为 PARALLEL RESTRICTED);文档总数排除 NULL 行,WAND 上界随 avgdl 漂移自动调整。 |
并发维护与 VACUUM |
第 4 版磁盘格式引入代际标记(generation stamp)、增长段与可崩溃恢复的待回收代际。VACUUM 与 bm25_maintain(regclass) 在基表 ShareUpdateExclusiveLock 下结合 GlobalVis 回收视界合并增长段,无需获取索引 AccessExclusiveLock 或分配事务 ID(XID);单独执行 ANALYZE 不触发重建。 |
| 物理备库回放 | VACUUM 仅对基表上已完成修剪(pruned)的 TID 写入墓碑,备库回放堆页修剪记录时已解决快照冲突;仅当页面回收复用旧代际且备库仍有旧查询在读该代际时返回 SQLSTATE 40001(serialization_failure)。 |
| 语料权限与 RLS | 索引扫描与标量 <&> 均检查当前角色的表级 SELECT 权限(普通单列非部分索引支持列级 SELECT),并在行级安全策略(RLS)生效时拒绝评分(0A000),防止通过全局语料统计信息产生侧信道泄漏;标量评分按“先锁基表、再锁索引”的顺序加锁。 |
| 构建与平台支持 | 升级至 pgrx 0.19.3,支持 Linux x86_64 与 aarch64 上的 PostgreSQL 14–18,支持运行时 SIMD 分发(AVX512 / AVX2 / NEON),并在页面锁外执行过滤谓词与中断检查。 |
原生 tsvector 索引与可迁移模式
在 vchord_bm25 1.0.0 中,文档直接存储为带词素位置(1..=16383,每个词素最多 256 个位置)的标准 PostgreSQL tsvector。计算词频(tf)和文档长度(dl)时,词素的每个位置条目计作一次出现;不带位置信息的词素不参与 BM25 计分。
由于直接作用于原生 tsvector,可以使用 PostgreSQL 内置的 to_tsvector(regconfig, text) 生成文档列,也可以搭配 pg_tokenizer 1.0.0(用 analyze_to_tsvector 生成字符串词素,或用 tokenize_to_tsvector 生成模型词元 ID 词素):
1.0.0 接口的几个主要变化:
- 查询构造器参数顺序:
to_bm25query(vector tsvector, index regclass)第一个参数为查询tsvector,第二个参数为目标索引regclass。该函数为STRICT,任一参数为NULL时返回NULL。 - 负数 BM25 分数:
<&>返回取反后的double precision(float8)BM25 分数,标准升序ORDER BY即可按相关性从高到低返回结果;零分统一返回+0.0。 - 支持模式迁移:所有类型、函数、操作符与
bm25访问方法均安装在扩展所在模式(默认public),支持通过ALTER EXTENSION vchord_bm25 SET SCHEMA <schema>;迁移。
包含 pg_tokenizer 多语言分词在内的完整示例,请参阅 BM25 索引指南与 BM25 查询指南。
可续扫的 WAND 检索、批次大小与共享统计缓存
在 0.3.x 中,bm25_catalog.bm25_limit 是单次索引扫描返回候选行的硬上限。当查询同时包含 ORDER BY ... <&> ... 与高选择率的 WHERE 过滤条件时,后置过滤可能筛掉大部分前排候选,导致最终返回行数少于 LIMIT。
在 1.0.0 中,bm25.limit(以及索引级 limit 存储参数)定义为 WAND 初始 top-K 批次大小:
- 按需续扫:当初始 WAND 批次消费完而执行器仍需更多行时(例如前排候选被
WHERE条件过滤,或查询请求了更大的LIMIT/OFFSET),扫描会自动继续向下遍历剩余匹配文档、零分文档与NULL行。 - 取值范围与优先级:
bm25.limit与索引limit选项均支持0..=65535(默认100);显式传入0时同样使用默认批次大小100。任何非默认值来源的 GUC 设置(会话SET、用户/数据库级设置或postgresql.conf)均优先于索引上的存储选项,包括显式设为0或false(bm25.enable_scan/bm25.prefilter)。由于limit是 SQL 保留关键字,在SET/SHOW/RESET中请使用双引号包裹"bm25.limit"。 - 共享统计信息与增长段缓存:语料统计信息(
N、avgdl与词项df)及增长段评分按(index, query)缓存在受work_mem限制的后端内存中(按最旧优先淘汰),并在同一次执行的索引扫描与SELECT列表 /WHERE子句中的标量<&>计算之间共享。统计计数包含所有非NULL物理记录(含合并前的墓碑,返回结果时立即跳过墓碑)。由于依赖后端缓存状态,<&>标记为PARALLEL RESTRICTED。 - 并发写入下的上界修正:当尚未合并的增长段新行改变了实时平均文档长度(
avgdl)时,WAND 词项上界会按比例调整,防止候选文档被提前剪枝。 - 优化器代价与快速取消:
amcostestimate仅对单键ORDER BY启用索引排序路径,支持在通用执行计划(generic plan)中识别to_bm25query(..., const regclass)。搜索循环在调用过滤谓词前先拷贝块跳转元数据并释放页面锁,在块间响应中断信号,使statement_timeout与pg_cancel_backend能立即生效。
并发维护、VACUUM 与物理备库回放
新插入与更新的行通过尾页提示追加写入增长段(growing segment),立即可被搜索,无需在每次前台写入时重写压缩倒排链。vchord_bm25 1.0.0 引入第 4 版磁盘格式,使段合并与空间回收能够与并发读写、并行 VACUUM、崩溃恢复及物理流复制备库协同工作:
- 自动与手动合并门槛:每个 BM25 索引支持
maintenance_min_rows(默认1000,范围0..=2147483647)和maintenance_scale_factor(默认0.1,范围0.0..=1.0)两个存储参数。当增长段记录数达到max(maintenance_min_rows, maintenance_scale_factor × 封闭段记录数),或墓碑数达到maintenance_scale_factor × 总记录数时,VACUUM会自动合并增长段并清理墓碑。调用SELECT bm25_maintain('documents_doc_bm25_idx'::regclass);会绕过门槛直接请求维护(发布了合并新段时返回true,无变化或上一待回收代际尚未回收时返回false;要求表所有者权限或 PostgreSQL 17+ 的MAINTAIN权限)。 - 无需索引
AccessExclusiveLock或分配事务 ID:VACUUM与bm25_maintain(regclass)仅持有基表的ShareUpdateExclusiveLock,并利用 PostgreSQL 的GlobalVis回收视界判断旧页面是否可安全复用,不会在索引上获取AccessExclusiveLock,也不会分配事务 ID(XID),可安全运行在并行VACUUM中。单独执行ANALYZE会直接返回,不触发索引重建。 - 可崩溃恢复的待回收代际(retired generation):发布合并新段时若仍有旧快照正在扫描上一代封闭段,索引会保留一个待回收代际,待后续维护确认旧快照全部结束后再回收旧页;在待回收代际回收完毕前若再次请求合并,维护会推迟而不会阻塞读写。
- 物理备库冲突处理:由于
VACUUM仅对基表上已完成修剪(heap prune)的 TID 写入墓碑,物理备库在回放先前的基表修剪 WAL 记录时已处理完快照冲突(与 PostgreSQL 原生nbtree一致)。仅当页面回收复用旧代际页面、而备库上仍有长查询正在读取该代际时,备库查询才会收到 SQLSTATE40001(serialization_failure)。
语料访问权限与行级安全策略(RLS)
BM25 分数依赖存储在索引中的全局语料统计信息(总文档数 N、平均文档长度 avgdl 以及词项文档频率 df)。如果标量 <&> 或索引扫描不校验基表权限,无权限角色或受行级安全策略(RLS)限制的角色就可能通过分数推算隐藏行的词频分布。
vchord_bm25 1.0.0 在索引扫描和独立标量 <&> 计算两条路径上统一检查权限:
- 表级与列级
SELECT权限检查:读取索引统计信息前,vchord_bm25会验证当前角色是否拥有被索引表的SELECT权限(对于普通单列、非部分索引,拥有被索引列的列级SELECT权限亦可;表达式索引与部分索引要求表级SELECT权限)。即使 SQL 不含FROM子句、仅对传入向量计算标量得分,也会执行该检查;仅拥有视图权限并不赋予底层语料访问权。 - 行级安全策略(RLS)限制:当行级安全策略适用于当前角色时,
vchord_bm25会以 SQLSTATE0A000(feature_not_supported)拒绝标量评分和原生索引扫描,防止跨受限行泄漏语料统计信息。表所有者和BYPASSRLS角色的豁免遵循 PostgreSQL 规则(启用FORCE ROW LEVEL SECURITY后普通表所有者同样受限);设置row_security = off不能绕过该检查。 - 加锁顺序:标量
<&>评分在锁定 BM25 索引前先锁定基表,遵循 PostgreSQL“先基表、后索引”的加锁顺序。
从 0.3.x 迁移与软件包获取
由于 vchord_bm25 1.0.0 更换了文档数据类型、扩展模式、查询构造函数参数顺序以及磁盘索引格式,0.3.0 -> 1.0.0 升级脚本在修改任何数据库对象前会主动报错终止 ALTER EXTENSION vchord_bm25 UPDATE,不会破坏现有数据。
| 特性 | vchord_bm25 0.3.x |
vchord_bm25 1.0.0 |
|---|---|---|
| 扩展模式 | 固定 bm25_catalog(relocatable = false) |
安装至目标模式(默认 public,relocatable = true) |
| 文档列类型 | bm25_catalog.bm25vector(token_id:freq 数组) |
PostgreSQL 原生 pg_catalog.tsvector(带词素位置) |
| 查询构造函数 | to_bm25query(regclass, bm25vector) |
to_bm25query(tsvector, regclass) |
| 分数返回类型 | real(float4) |
double precision(float8,零分统一为 +0.0) |
| GUC 参数 | bm25_catalog.bm25_limit、bm25_catalog.enable_index |
"bm25.limit"、bm25.enable_scan、bm25.prefilter |
| 段维护方式 | 需执行 REINDEX 才能手动合并增长段 |
bm25_maintain(regclass) + VACUUM 自动合并门槛 |
从 0.3.x 迁移时,请保留原始文本列,在具有独立扩展库目录的新 PostgreSQL 安装或容器环境中安装 1.0.0 软件包,生成原生 tsvector 列并重建 USING bm25 (doc bm25_ops) 索引。详细步骤请参阅 BM25 迁移指南。
面向 PostgreSQL 14–18、覆盖 16 个 Linux 发行版(x86_64 与 aarch64)的原生 RPM 与 DEB 软件包(1.0.0-1PIGSTY / 1.0.0-1PGSTY)已发布在下载页面。更多配置细节请参阅 BM25 SQL 参考、GUC 参数参考与 SBOM 页面。