PostgreSQL全文搜索基于文本向量和查询向量进行匹配,默认的english或simple配置只做基础分词和词干处理,无法识别业务术语中的同义表达。例如查询手机号时输入手机号码、电话号码、联系方式,默认检索可能只命中完全匹配的文档。要解决这一问题,需要借助同义词词典把多个词映射到同一词位,同时利用字典扩展控制分词结果。

全文搜索的文本解析与字典机制
PostgreSQL在执行to_tsvector时会先调用文本解析器把文本拆分成token,然后根据文本检索配置依次应用映射字典。每一个token经过字典处理后可能生成一个或多个词位,最终这些词位组成tsvector。理解这个过程非常重要,因为它决定了同义词词典应该放在哪个环节、是否需要保留原始词形。
系统默认的文本检索配置通常由解析器、分词字典和停止词字典组成。通过命令\dF+ english可以查看英文配置的字典顺序。对于中文内容,官方解析器默认按空格分词,因此如果直接处理连续中文文本,需要先扩展解析器或配合其他分词插件。本文示例以英文和业务术语为主,便于说明字典机制,中文场景可以在分词之后再接入同义词规则。
字典在配置中的顺序会直接影响最终词位。简单来说,如果某个字典返回了词位数组,后续字典不会继续处理该token。因此同义词词典通常放在普通词干字典之前,先把同义词规范成统一形式,再交给词干处理。对于不希望被后续字典改变的业务编码或型号,也可以使用simple字典直接输出原始词形。
配置同义词词典实现业务术语归一
同义词词典的配置文件默认位于PostgreSQL数据目录下的tsearch_data文件夹中,扩展名为.syn。创建文件后需要向数据库注册字典,并把字典加入文本检索配置。假设业务中需要把手机号、手机号码、联系电话、contact统一归一为phone,可以新建一个名为business_syn.syn的文件。文件格式为每行一个规则,第一个词是规范化后的目标词,后面列出所有同义词,多个词之间用空格分隔。
-- 创建同义词字典
CREATE TEXT SEARCH DICTIONARY business_syn (
TEMPLATE = synonym,
SYNONYMS = business_syn
);
-- 创建文本检索配置
CREATE TEXT SEARCH CONFIGURATION business_cfg (COPY = pg_catalog.english);
-- 将同义词字典放到配置最前面
ALTER TEXT SEARCH CONFIGURATION business_cfg
ALTER MAPPING FOR asciiword, word, numword, hword
WITH business_syn, english_stem;
上面的SQL注册了同义词字典,并复制english配置创建business_cfg。ALTER MAPPING表示对解析器产生的asciiword、word等token类型先使用business_syn,再使用english_stem。需要注意,如果同义词字典已经返回了映射后的词位,则不会继续执行english_stem,这正符合我们想要保留归一结果的需求。
配置文件business_syn.syn的示例内容如下,每一行首列是目标词位,后续列是需要被替换的同义词。目标词只能有一个,同义词可以有多个。
phone 手机号 手机号码 联系电话 contact computer 电脑 计算机 微机
创建配置文件后需要确保文件权限允许PostgreSQL进程读取。注册字典不会自动加载文件内容,但每次查询会根据文件动态读取,修改后无需重新创建字典。可以使用to_tsvector函数验证配置效果,查询手机号、手机号码、联系电话等应得到相同的词位phone。
SELECT to_tsvector('business_cfg', '请拨打手机号或联系电话');
SELECT to_tsquery('business_cfg', '手机号码');
如果输出中多个中文词都对应phone,说明同义词规则生效。实际项目中可以把客户提供的同义词表整理成.syn文件,批量导入。维护时建议把同义词文件纳入版本控制,并在修改后执行一次回归查询,避免错误映射导致搜索质量下降。
自定义字典扩展停用词与词形处理
除了同义词,全文搜索还经常需要停用词字典过滤无意义词,或使用Ispell和Snowball字典做更细致的词干处理。PostgreSQL提供了多种字典模板,包括simple、synonym、thesaurus、ispell和snowball。simple字典直接输出原词,不做变化;snowball适合英文等语言,可以根据语言规则提取词干;thesaurus适合短语级同义替换,例如把全球定位系统替换为GPS,再继续分词典处理。
对于电商搜索中的型号词,比如iPhone 15 Pro,解析器可能把iPhone识别成asciiword,15识别成numword,Pro识别成asciiword。此时如果希望整个型号作为一个词位,可以使用thesaurus字典在解析后做短语替换。配置一个thesaurus文件,规则格式为:原始短语 : 替换词。这样to_tsvector会先把短语合并,再进行后续字典处理。
全球定位系统 : gps 移动电话 : phone
把thesaurus字典加入配置时,必须放在synonym和stem之前,因为短语替换需要在token被分拆后立即执行。配置顺序示例如下:先使用thesaurus,再使用synonym,最后使用english_stem。这样既能处理短语,又能处理单词同义词和词干。
CREATE TEXT SEARCH DICTIONARY business_thes (
TEMPLATE = thesaurus,
DictFile = business_thes,
Dictionary = pg_catalog.english_stem
);
ALTER TEXT SEARCH CONFIGURATION business_cfg
ALTER MAPPING FOR asciiword, word, numword, hword
WITH business_thes, business_syn, english_stem;
这个配置中Dictionary参数指定thesaurus替换后继续使用的字典,通常填写english_stem。如果不需要继续词干化,可以简单使用simple。需要注意的是,thesaurus的Dictionary参数在不同版本中的语义略有差异,配置后应使用to_tsvector验证短语是否被正确合并。
多语言场景与查询性能优化
当业务涉及多种语言时,可以为不同语言创建不同的文本检索配置,再根据文档语言列选择合适的配置。比如产品表包含language字段,索引时需要为每种语言单独创建表达式索引。以中文、英文混合为例,中文需要先解决分词问题,英文使用stem处理,业务术语则通过同义词字典统一。这样可以在一个搜索接口中根据用户输入语言切换配置。
CREATE INDEX idx_product_search_en ON product
USING gin (to_tsvector('business_cfg_en', title || ' ' || description));
CREATE INDEX idx_product_search_zh ON product
USING gin (to_tsvector('business_cfg_zh', title || ' ' || description));
表达式索引要求查询条件中的to_tsvector表达式与索引完全一致,否则无法使用索引。因此应用层需要根据语言参数动态选择配置名。查询时可以使用to_tsquery生成查询向量,并通过@@操作符匹配。对于同义词场景,to_tsquery也会经过同义词字典,因此即使用户输入手机号码,也能匹配到存储时归一为phone的文档。
性能方面,GIN索引对全文搜索非常高效,但索引构建和更新成本较高。建议在数据导入完成后再创建索引,并对高频更新表使用延迟索引或分区表。可以通过EXPLAIN ANALYZE查看查询是否走索引,避免函数包裹导致全表扫描。如果同义词文件频繁变化,可以使用pg_ts_dict视图监控字典状态,但真正生效时间取决于查询时读取文件,无需重启数据库。
最后要提醒的是,同义词映射是一把双刃剑。过度归一可能让搜索失去区分度,例如把苹果同时映射到水果和手机品牌会干扰结果。实际使用中应根据业务域控制同义词范围,必要时为不同业务建立不同配置,而不是把所有同义词堆在一个字典中。通过合理组织字典文件、控制配置顺序并定期回归验证,可以构建一套稳定且可解释的全文搜索方案。
PostgreSQL全文搜索同义词词典文本检索配置修改时间:2026-08-28 22:32:06