You need to enable JavaScript to run this app.
文档中心
AI 原生 BaaS 平台 Supabase 版

AI 原生 BaaS 平台 Supabase 版

复制全文
下载 pdf
插件
全文检索(pg_textsearch)
复制全文
下载 pdf
全文检索(pg_textsearch)
本文介绍如何使用 pg_textsearch 插件创建 BM25 全文索引,并按相关性返回检索结果。​
功能简介​
pg_textsearch 是一款适用于 PostgreSQL 的全文检索插件。该插件使用 BM25 算法计算文本与检索词的相关性,支持按相关性排序并返回 Top-K 结果。​
插件支持以下能力:​
  • 支持为 text、text[] 类型、文本表达式及 JSON 文本字段创建 BM25 索引。​
  • 使用 PostgreSQL 文本搜索配置(Text Search Configuration) 完成分词、词干提取和停用词处理。​
  • 通过部分索引(Partial Index)为多语言数据分别配置分词方式。​
说明​
pg_textsearch 插件当前仅在华东 2(上海)和亚太东南(柔佛)地域提供。​
前提条件​
  • 在 2026.10.19 之后创建 Workspace 默认支持该插件。如需在 2026.10.19 及之前创建的 Workspace 中使用该插件,需重启目标分支的算力。​
  • 创建插件需要使用具备相应权限的数据库账号。​
  • 创建索引前,请根据文本语言选择文本搜索配置(Text Search Configuration)。例如,英文可使用 english。​
  • 使用中文分词前,需加载 pg_jieba 插件。​
安装与卸载插件​
安装插件​
在需要使用全文检索的数据库中执行以下命令:​
​
CREATE EXTENSION pg_textsearch;​
​
执行以下命令,确认插件已创建并查看插件版本:​
​
SELECT extname, extversion​
FROM pg_extension​
WHERE extname = 'pg_textsearch';​
​
查询返回 pg_textsearch 及其版本号,表示插件已创建。​
卸载插件​
如您已确认不再需要 pg_textsearch 插件,可在安装了 pg_textsearch 的数据库中执行以下命令卸载插件:​
​
DROP EXTENSION pg_textsearch;​
​
创建索引​
索引语法和参数​
​
CREATE INDEX index_name​
ON table_name USING bm25 (text_column_or_expression)​
WITH (​
text_config = 'text_search_configuration',​
k1 = 1.2,​
b = 0.75​
);​
​
​
参数​
默认值​
说明​
text_config​
无,必填​
PostgreSQL 文本搜索配置(Text Search Configuration)名称,决定索引和查询时如何分词、词干提取和过滤停用词。​
常用值:​
  • 英文填 english。​
  • 中文搭配 pg_jieba 插件时填 public.jiebacfg。​
  • 其他语言或自定义配置填对应分词器的 schema.cfgname。​
k1​
1.2​
词频饱和参数,范围 0.1~10.0。越大越强调词频,但收益会逐渐饱和。​
b​
0.75​
文档长度归一化参数,范围 0.0~1.0。0 表示不按长度归一化,1 表示完全归一化。​
​
text_config 必须填写当前数据库中已经存在的文本搜索配置。可用以下 SQL 查看可填写的配置名:​
​
SELECT n.nspname AS schema_name, c.cfgname​
FROM pg_ts_config c​
JOIN pg_namespace n ON n.oid = c.cfgnamespace​
ORDER BY 1, 2;​
​
注意​
text_config、k1 和 b 都会写入索引元数据。修改它们需要重建索引,修改词典或 PostgreSQL 文本搜索配置(Text Search Configuration)后,已存在的 BM25 索引不会自动重新分词。​
创建表达式索引​
表达式结果必须是 text 或 text[],并满足 PostgreSQL 对索引表达式不可变性(IMMUTABLE)的要求。若需覆盖多列,可将多列拼接为文本表达式后建索引。查询时,ORDER BY 中用于评分的表达式须与索引表达式匹配:​
​
CREATE INDEX articles_title_body_bm25_idx​
ON articles USING bm25 (​
(coalesce(title, '') || ' ' || coalesce(body, ''))​
)​
WITH (text_config = 'english');​
​
SELECT id, title​
FROM articles​
ORDER BY (coalesce(title, '') || ' ' || coalesce(body, ''))​
<@> to_bm25query('postgres search', 'articles_title_body_bm25_idx')​
LIMIT 10;​
​
JSONB 字段也可以通过表达式建立索引:​
​
CREATE INDEX events_description_bm25_idx​
ON events USING bm25 ((data ->> 'description'))​
WITH (text_config = 'english');​
​
创建 text[] 索引​
text[] 元素会先用空格连接成一个逻辑文档,再统一分词并参与 BM25 评分;并非逐元素独立调用分词器。数组元素边界会成为空白边界提示,适合由应用预先划分段落、标题或消息块的大文档,但不保证每个元素独占一个内部 chunk:​
​
CREATE TABLE chunked_documents (​
id bigserial PRIMARY KEY,​
content_chunks text[] NOT NULL​
);​
​
CREATE INDEX chunked_documents_bm25_idx​
ON chunked_documents USING bm25 (content_chunks)​
WITH (text_config = 'english');​
​
创建中文 BM25 索引​
中文内容通常需要显式选择中文分词配置。pg_textsearch 通过 PostgreSQL 文本搜索配置(Text Search Configuration)决定索引和查询时的分词规则,中文检索建议搭配 pg_jieba 插件,并在建立 BM25 索引时指定 public.jiebacfg 分词规则。可使用以下命令加载 pg_jieba 插件:​
​
CREATE EXTENSION IF NOT EXISTS pg_jieba CASCADE;​
​
建立使用 pg_jieba 作为中文分词器的 BM25 索引:​
​
CREATE INDEX chinese_documents_bm25_idx​
ON chinese_documents USING bm25 (content)​
WITH (text_config = 'public.jiebacfg');​
​
​
查询​
自动识别索引​
普通 SQL 中可以直接把检索文本写在 <@> 右侧,规划器会根据左侧列或表达式自动识别 BM25 索引:​
​
SELECT id, content​
FROM documents​
ORDER BY content <@> 'postgres database'​
LIMIT 10;​
​
自动识别索引的查询方式语法简洁,适用于单表、普通索引、固定查询文本的常规 Top-K 查询。以下复杂场景建议显式指定索引:​
  • 部分索引(Partial Index)​
  • PL/pgSQL 的 DO、函数或存储过程​
  • Prepared Statement 或检索词来自参数、子查询等动态表达式​
  • 同一列存在多个 BM25 索引,需要消除索引选择歧义​
  • 表达式较复杂,或需要让 SQL 明确绑定某个索引​
​
显式指定索引​
​
SELECT id, content​
FROM documents​
ORDER BY content <@> to_bm25query(​
'postgres database',​
'documents_content_bm25_idx'​
)​
LIMIT 10;​
​
PL/pgSQL 和 Prepared Statement 中建议始终使用显式形式:​
​
PREPARE search_documents(text, int) AS​
SELECT id, content​
FROM documents​
ORDER BY content <@> to_bm25query($1, 'documents_content_bm25_idx')​
LIMIT $2;​
​
分数展示​
由于索引按升序返回结果,<@> 的输出是负 BM25 分数:​
​
SELECT id,​
content <@> to_bm25query('database', 'documents_content_bm25_idx')​
AS sort_score,​
-(content <@> to_bm25query('database', 'documents_content_bm25_idx'))​
AS bm25_score​
FROM documents​
ORDER BY sort_score​
LIMIT 10;​
​
中文检索​
​
SELECT id, content,​
content <@> '云数据库全文检索' AS score​
FROM chinese_documents​
ORDER BY content <@> '云数据库全文检索'​
LIMIT 10;​
​
索引和查询必须使用兼容的分词配置。​
使用 pg_jieba 插件默认的 jiebacfg 配置时,查询文本中的 ASCII 空格可能被解析为额外词元,造成非预期召回;中文查询建议直接连续书写,或先用 to_tsvector('public.jiebacfg', query_text) 检查实际词元。中文、英文或其他语言共用同一张表时,建议按语言创建 Partial Index,并通过 to_bm25query() 显式绑定对应语言索引。​
部分索引(Partial Index)​
部分索引(Partial Index) 只保存满足谓词的行。使用 Partial Index 时,需要在查询的 WHERE 中包含创建索引时的过滤条件,并通过 to_bm25query() 显式指定索引。例如,索引使用 WHERE lang = 'zh',查询时也应包含 WHERE lang = 'zh'。​
中文内容可以在已安装 pg_jieba 插件的前提下使用 public.jiebacfg 创建语言专属索引:​
​
CREATE INDEX documents_zh_bm25_idx​
ON documents USING bm25 (content)​
WITH (text_config = 'public.jiebacfg')​
WHERE lang = 'zh';​
​
SELECT id, content​
FROM documents​
WHERE lang = 'zh'​
ORDER BY content <@> to_bm25query('数据库', 'documents_zh_bm25_idx')​
LIMIT 10;​
​
其他语言可以使用对应的 PostgreSQL 文本搜索配置(Text Search Configuration)创建独立索引:​
​
CREATE INDEX documents_en_bm25_idx​
ON documents USING bm25 (content)​
WITH (text_config = 'english')​
WHERE lang = 'en';​
​
SELECT id, content​
FROM documents​
WHERE lang = 'en'​
ORDER BY content <@> to_bm25query('database', 'documents_en_bm25_idx')​
LIMIT 10;​
​
​
性能调优建议​
pg_textsearch.default_limit​
ORDER BY ... LIMIT n 是 pg_textsearch 的推荐查询形态。规划器能安全下推 LIMIT 时,Block-Max WAND 只维护 Top-K 候选,并跳过不可能进入Top-K 的 posting blocks,通常能显著减少评分量,大幅提升性能。​
​
SELECT id, content​
FROM documents​
ORDER BY content <@> 'database system'​
LIMIT 20;​
​
​
当规划器没有取得可安全下推的 SQL LIMIT 时(例如部分 Prepared Statement 场景),由 pg_textsearch.default_limit 决定 BM25 扫描的初始内部 Top-K 批次大小,因此过高的 pg_textsearch.default_limit 可能增加评分成本,并最终导致查询性能下降。​
建议:​
  • 在线 Top-K 检索始终写显式 LIMIT,明确返回行数上限,并为 Top-K 下推优化提供条件。​
  • 规划器无法安全下推 LIMIT 时,将 default_limit 调整为接近业务常用 LIMIT 的取值。​
  • 调整 default_limit 后,使用代表性查询和 EXPLAIN (ANALYZE, BUFFERS) 比较执行计划、查询耗时以及过滤行数。​
​
SHOW pg_textsearch.default_limit;​
​
BEGIN;​
SET LOCAL pg_textsearch.default_limit = 500;​
​
SELECT id, content​
FROM documents​
ORDER BY content <@> 'database system';​
​
COMMIT;​
​
如果希望修改某个业务账号的默认值,可在评估后按角色设置:​
​
ALTER ROLE app_user SET pg_textsearch.default_limit = 500;​
​
​
查询写法与过滤条件​
优先把检索写成 ORDER BY ... <@> ... LIMIT n。只写 WHERE 条件不能触发 BM25 Top-K 排序能力,也无法让 Block-Max WAND 按 Top-K 剪枝。​
​
SELECT id, content​
FROM documents​
ORDER BY content <@> to_bm25query('database system', 'documents_content_bm25_idx')​
LIMIT 20;​
​
如果查询同时带有高选择性过滤条件,可以为过滤列建立普通 B-tree 索引,或按稳定条件创建 Partial Index。规划器可能选择 B-tree/Bitmap 路径先过滤,再对较少行逐行计算 BM25 并排序;这种计划不使用 BM25 Index Scan 或 Block-Max WAND。应通过 EXPLAIN (ANALYZE, BUFFERS) 比较它与 BM25 Index Scan 后置过滤的实际代价:​
​
CREATE INDEX documents_category_id_idx ON documents (category_id);​
​
SELECT id, content​
FROM documents​
WHERE category_id = 123​
ORDER BY content <@> to_bm25query('database system', 'documents_content_bm25_idx')​
LIMIT 20;​
​
当过滤条件位于 BM25 Index Scan 之上时,pg_textsearch 会根据过滤选择率扩大初始候选集,并在过滤后结果不足时自动倍增内部 Top-K、重新评分,直到满足 SQL LIMIT、候选耗尽或达到内部上限。默认开启 pg_textsearch.filtered_seed,pg_textsearch.filtered_seed_margin 默认为 3。只要存在足够的匹配行,通常无需手工用子查询放大候选集;手工截断候选反而可能遗漏排在截断点之后的合格结果。​
​
SHOW pg_textsearch.filtered_seed;​
SHOW pg_textsearch.filtered_seed_margin;​
​
BEGIN;​
SET LOCAL pg_textsearch.filtered_seed = on;​
SET LOCAL pg_textsearch.filtered_seed_margin = 3;​
​
EXPLAIN (ANALYZE, BUFFERS)​
SELECT id, content​
FROM documents​
WHERE category_id = 123​
ORDER BY content <@> to_bm25query(​
'database system', 'documents_content_bm25_idx'​
)​
LIMIT 20;​
​
ROLLBACK;​
​
​
分词配置与文档粒度​
分词配置会直接影响 token 数量、倒排列表长度和评分质量。应使用与数据语言一致的 text_config,避免英文配置索引中文内容,或把多语言内容混在同一个索引中评分。多语言表建议按语言拆分 Partial Index,中文示例见创建中文 BM25 索引和中文检索两节。​
超大文档会增加单行分词、写入和评分成本。如果业务天然有段落、标题、正文块或消息分片边界,可考虑使用 text[] 存储预切分内容。pg_textsearch 会先用空格连接数组元素,再按与普通 text 相同的规则统一分词和切块;元素边界可为无空格语言提供额外的空白切块提示,但不会让每个元素独立分词或保证独占一个内部 chunk。​
常用参数参考​
查看当前参数值:​
​
SELECT name, setting, unit, context, vartype, boot_val, reset_val​
FROM pg_settings​
WHERE name LIKE 'pg_textsearch.%'​
ORDER BY name;​
​
​
参数​
默认值​
取值范围​
生效范围​
说明​
pg_textsearch.default_limit​
1000​
1~100000​
用户/会话​
没有取得可安全下推的 SQL LIMIT 时,作为 BM25 扫描的初始内部 Top-K 批次大小。批次耗尽后可能倍增扩容,最高到 100000。​
pg_textsearch.filtered_seed​
on​
on / off​
用户/会话​
根据过滤选择率估算并扩大初始内部 Top-K,减少过滤查询的回退重算。​
pg_textsearch.filtered_seed_margin​
3​
1~1000​
用户/会话​
计算过滤查询初始候选深度时使用;值越大,首次评分越深,但通常能减少回退次数。​
pg_textsearch.compress_segments​
​
on​
​
on / off​
用户/会话​
控制新生成 segment 是否压缩 posting blocks。修改后只影响新 segment。​
pg_textsearch.memtable_cache_enabled​
on​
​
on / off​
用户/会话​
查询是否使用共享内存派生缓存读取 memtable;关闭后强制走 on-disk memtable chain,只读备库会自动绕过 cache。​
​
​
限制与注意事项​
  • 暂不原生支持短语位置匹配;可先用 BM25 过量召回,再用 ILIKE 或业务逻辑后置过滤。​
  • 写入高峰期间,索引维护操作可能导致写入延迟波动;初始大批量数据优先先导入、后建索引。​
  • 分区表的 BM25 文档数、平均文档长度和 IDF 统计按分区维护;跨分区分数可能不在同一评分尺度上。​
  • 单个 token 继承 PostgreSQL tsvector 的 2047 字节长度限制,超长 token 会被忽略。​
  • 超大文档会统一分块分词;无空格语言可能在内部切块边界处切断词语。应用可预切分为 text[] 并搭配相应分词器,数组元素间插入的空格可提供额外切块边界提示,但元素仍会连接成一个逻辑文档,不会逐元素独立分词。​
  • 自动识别索引语法不适用于 Partial Index,且在 PL/pgSQL、Prepared Statement 和部分动态表达式场景中应改用显式索引名。​
最近更新时间:2026.10.22 20:01:17
这个页面对您有帮助吗?
有用
有用
无用
无用