Nova BM25索引和词典管理

更新时间:
复制 MD 格式

本文介绍如何创建和管理 Nova BM25 全文检索索引,以及如何配置中文分词词典。Nova BM25 是 AnalyticDB PostgreSQL 提供的高性能全文检索方案,基于 nova_bm25 扩展实现,SQL 函数位于 bm25 schema,索引访问方法名为 nova_bm25。

有关 Nova BM25 的快速入门指南,请参见Nova BM25快速开始。有关完整的函数 API 参考,请参见Nova BM25 Function API参考。

创建索引

创建示例表

以下示例创建一个包含多种字段类型的业务表,涵盖文本、数值、时间戳和布尔类型,作为后续索引创建的参考:

CREATE TABLE docs (
    id         bigint PRIMARY KEY,
    title      text,
    body       text,
    category   text,
    rating     integer,
    publish_at timestamp,
    in_stock   boolean
) DISTRIBUTED BY (id);

创建 BM25 索引

在示例表上创建 Nova BM25 索引,通过 WITH 子句为每种字段类型指定相应的索引配置。正确的字段配置直接影响检索的准确性和性能:

CREATE INDEX docs_bm25_idx ON docs
USING nova_bm25 (title, body, category, rating, publish_at, in_stock)
WITH (
    text_fields = '{
      "title": {"tokenizer": {"type": "jieba"}},
      "body": {"tokenizer": {"type": "jieba"}},
      "category": {"tokenizer": {"type": "keyword"}}
    }',
    numeric_fields = '{"rating": {}}',
    datetime_fields = '{"publish_at": {}}',
    boolean_fields = '{"in_stock": {}}'
);

索引字段配置说明

创建索引时,需要通过 WITH 子句为每个参与检索的字段指定配置。下表列出各类字段配置参数的详细说明:

配置参数

适用字段类型

说明

配置示例

text_fields

text、varchar

文本字段,需指定 tokenizer 类型以控制分词方式

{"title": {"tokenizer": {"type": "jieba"}}}

numeric_fields

integer、bigint、float 等

数值字段,支持范围查询和数值排序

{"rating": {}}

datetime_fields

timestamp、date

时间字段,支持时间范围查询

{"publish_at": {}}

boolean_fields

boolean

布尔字段,支持 true/false 过滤

{"in_stock": {}}

json_fields

json、jsonb

JSON 字段,支持对 JSON 内部键值建立索引

{"metadata": {}}

选择字段配置

为每个字段选择正确的配置类型是构建高效全文索引的关键。配置类型决定了字段的检索行为和可用的查询方式。下表列出常见的字段用途及其推荐的配置方式:

字段用途

配置方式

示例

中文标题、正文

text_fields,使用 jieba

title、body

分类、状态等整值字段

text_fields,使用 keyword

category、status

评分、价格等数值字段

numeric_fields

rating、price

发布时间等时间字段

datetime_fields

publish_at

是否上架等布尔字段

boolean_fields

in_stock

JSON 字段

json_fields

metadata

文本字段 tokenizer 选择指南

为文本字段选择正确的 tokenizer 直接影响检索效果。下表列出常用的 tokenizer 类型及其适用场景:

Tokenizer 类型

适用场景

说明

jieba

中文文本

基于结巴分词,支持中文语义分词,可加载自定义词典

default

英文文本

按空格和标点符号分词,适用于英文等西文语言

keyword

精确匹配字段

不分词,将整个字段值作为一个检索单元,适用于分类、标签、状态码等

ngram

细粒度匹配

按 n-gram 切分文本,支持部分匹配和模糊检索,适用于前缀或子串搜索场景

验证分词效果

创建索引后,建议使用分词调试函数验证实际的分词效果是否符合预期。以下示例展示如何查看 jieba 分词器对输入文本的分词结果:

SELECT * FROM bm25.debug_tokenizer('云原生数据库', 'jieba');

查询增量数据

Nova BM25 支持近实时查询模式,新写入或更新的数据在短暂的延迟后即可被检索到。您可以通过以下参数和命令控制增量数据的查询行为,在数据新鲜度与查询性能之间取得平衡。

通过 query_skip_mutable 参数控制是否查询最新增量数据:

参数

说明

query_skip_mutable

默认值为 true,使用默认近实时查询模式。设置为 false 时包含最新增量数据,但可能增加查询延迟。

在创建索引时设置该参数:

CREATE INDEX docs_bm25_idx ON docs
USING nova_bm25 (title, body)
WITH (text_fields = '{"title": {"tokenizer": {"type": "jieba"}}, "body": {"tokenizer": {"type": "jieba"}}}', query_skip_mutable = false);

通过 ALTER INDEX 修改该参数:

ALTER INDEX docs_bm25_idx SET (query_skip_mutable = false);
ALTER INDEX docs_bm25_idx SET (query_skip_mutable = true);

通过 SET 命令在会话级别控制:

SET nova_bm25.query_include_mutable = on;
RESET nova_bm25.query_include_mutable;

修改和重建索引

Nova BM25 索引创建后,其字段配置(如 tokenizer 类型、字段映射等)不支持通过 ALTER INDEX 直接修改。如需变更索引配置,必须先删除索引再重新创建。

删除并重新创建索引以修改配置:

DROP INDEX docs_bm25_idx;
-- 重新创建
CREATE INDEX docs_bm25_idx ON docs USING nova_bm25 (...) WITH (...);

如果索引配置无需变更,但需要清理索引碎片或刷新索引数据,可以使用 REINDEX 命令重建索引:

REINDEX INDEX docs_bm25_idx;

中文词典管理

Nova BM25 使用 jieba 分词器处理中文文本。为了满足业务场景中的专业术语和同义词检索需求,您可以通过词典管理功能自定义分词行为。

添加自定义词条

向 jieba 分词器的自定义词典中添加专业术语或业务词汇,使分词器能够正确识别这些词条,避免被错误切分。添加后需要重新加载词典使其生效:

SELECT bm25.add_dict_word('jieba', 'product_terms', '云原生数据库', 10000, 'n');
SELECT bm25.reload_dict('jieba', 'product_terms');

配置同义词

配置同义词词典,将多个含义相近的词条映射到相同的检索结果,从而扩大搜索覆盖面,提升召回率:

SELECT bm25.add_dict_word('synonym', 'product_synonyms', 'postgresql,postgres,pg');
SELECT bm25.reload_dict('synonym', 'product_synonyms');

验证词典效果

添加自定义词条或同义词后,建议通过分词调试函数验证词典配置是否生效,确认词条被正确识别:

SELECT * FROM bm25.debug_tokenizer('云原生数据库', 'jieba');

日常维护

定期执行维护操作有助于保持 Nova BM25 索引的查询性能和数据一致性。下表列出常用的维护操作及其用途:

操作

说明

VACUUM

回收已删除数据占用的空间,优化表存储

REINDEX

重建索引以消除碎片,恢复查询性能

DROP INDEX

删除不再使用的索引,释放存储空间

VACUUM docs;
REINDEX INDEX docs_bm25_idx;
DROP INDEX docs_bm25_idx;