PostgreSQL全文搜索:如何拆分无空格连接的数字与单位词汇
PostgreSQL全文搜索:拆分数字与紧连单位为独立词素
要实现to_tsvector('10ml')返回'10':1 'ml':2,同时兼容带空格的格式(如10 ml),可通过以下方案实现:
核心限制说明
默认PostgreSQL文本搜索解析器会将10ml识别为单一的numword类型token,而文本搜索字典仅能修改或替换token,无法拆分token。因此纯通过修改现有配置项无法直接实现,需通过扩展解析器或自定义逻辑完成。
方案1:自定义文本搜索解析器(纯配置扩展)
若希望完全通过修改文本搜索配置实现,需编写C语言扩展创建自定义解析器,定义词法规则将数字与紧连单位拆分为独立token:
- 编写C扩展代码,实现词法分析逻辑,识别数字段与单位段并输出独立token。
- 编译安装扩展后,将自定义解析器注册到PostgreSQL。
- 创建基于该解析器的文本搜索配置,搭配目标字典(如
simple或english)。 - 使用该配置执行
to_tsvector('custom_config', '10ml')即可得到拆分结果。
此方案完全符合配置修改需求,但需要具备PostgreSQL扩展开发能力。
方案2:自定义分词函数(折中实用方案)
若不想编写C扩展,可通过自定义SQL函数实现拆分逻辑,封装后替代默认to_tsvector:
- 创建拆分函数,用正则识别并拆分数字+单位组合:
CREATE OR REPLACE FUNCTION split_num_unit(input_text text) RETURNS text[] AS $$ SELECT ARRAY( -- 提取数字和单位 SELECT regexp_replace(match, '^(\d+)([a-zA-Z]+)$', '\1|\2') FROM regexp_matches(input_text, '\d+[a-zA-Z]+', 'g') AS matches(match) UNION ALL -- 保留其他文本内容 SELECT unnest(regexp_split_to_array(input_text, '\d+[a-zA-Z]+')) ) WHERE input_text ~ '\d+[a-zA-Z]+'; $$ LANGUAGE sql IMMUTABLE;
- 创建自定义
to_tsvector包装函数:
CREATE OR REPLACE FUNCTION custom_to_tsvector(input_text text) RETURNS tsvector AS $$ SELECT COALESCE(array_to_tsvector(split_num_unit(input_text)), '') || to_tsvector('english', input_text); $$ LANGUAGE sql IMMUTABLE;
- 调用测试:
SELECT custom_to_tsvector('10ml'); -- 返回结果:'10':1 'ml':2 SELECT custom_to_tsvector('10 ml'); -- 返回结果:'10':1 'ml':2
该方案兼顾需求与实现复杂度,可统一处理带空格和无空格的格式。
内容的提问来源于stack exchange,提问作者Viktor Holmberg
相关产品推荐
相关产品推荐

