常见原因是ts_vector与ts_query配置不匹配,如english与simple混用;需统一配置、检查不可见字符;自定义高亮须成对指定标签且无空格;plainto_tsquery对连字符处理不佳,建议改用websearch_to_tsquery;性能差因重复解析,宜用生成列+GIN索引优化。
为什么
返回空字符串或原始文本
常见原因是文档和查询的
/
使用了不匹配的文本搜索配置(如
vs
)。
不会自动转换语言规则,它只在给定配置下匹配词干和停用词。比如用
生成向量,但用
查询,就无法命中——因为
不做词干化,且大小写敏感。
实操建议:
确保
的第三个参数(配置名)与构建
和
时一致,例如统一用
若字段未预建
列,直接在查询中调用
,别漏掉配置参数
检查目标字段是否含不可见字符(如零宽空格),
对非法 UTF-8 或控制字符可能静默失败
如何自定义高亮标记而不依赖默认的
支持通过选项参数替换默认标签,但必须成对指定:起始标记和结束标记。它不接受单个标签,也不支持嵌套 HTML 属性(如
)——这些会被原样输出,不解析为 HTML 属性。
实操建议:
用
替换默认的
,注意等号前后**不能有空格**,且引号需匹配外层 SQL 字符串
若需加 class,只能写成
,但双引号必须用
转义,否则 SQL 解析报错
避免使用
等语义过强的标签;前端渲染时若已用 CSS 控制样式,纯文本标记(如
/
)反而更安全、易清洗
为什么
匹配不到带连字符的词(如 “e-mail”)
默认按空格和标点切分词元,但连字符在多数配置(如
)中被视作分词符,导致 “e-mail” 被拆成
和
两个独立词元。而原文本中的
可能保留了完整 token(取决于字典规则),造成查询与向量不一致。
实操建议:
改用
或
,后者对连字符更宽容,且支持自然语言语法(如引号短语)
若必须用
,先对用户输入做预处理:用正则将
→
,再传入函数
测试时用
验证是否返回
,避免上线后才发现漏匹配
高亮性能差?别在 SELECT 中反复调用
每次调用
都触发全文解析、词干化、停用词过滤——对长文本或大结果集,CPU 开销显著。尤其当
字段未索引、且 WHERE 条件又靠
匹配时,数据库可能先全表扫描再高亮,双重低效。
实操建议:
为高频搜索字段添加生成列:
,并在此列上建 GIN 索引
查询时用
过滤,再用
高亮——避免重复解析同一字段
如果
更新频繁,生成列自动维护,无需应用层干预;但注意
会占用额外磁盘空间
复杂点在于配置一致性与标记安全性之间要取舍:严格按配置走才能准确匹配,但前端渲染时又得防 XSS——所以标记尽量用无属性纯文本,由前端决定如何包装。
ts_headline()tsvectortsqueryenglishsimplets_headline()to_tsvector('english', 'running')to_tsquery('simple', 'run')simplets_headline()tsvectortsquery'english'tsvectorto_tsvector('english', body)ts_headline()ts_headline()class="highlight"ts_headline(body, q, 'StartSel= StopSel=')StartSel="[[[]]]plainto_tsquery()plainto_tsquery()englishemailto_tsvector()phraseto_tsquery()websearch_to_tsquery()plainto_tsquery()e-mail"e-mail"SELECT to_tsvector('english', 'send e-mail now') @@ plainto_tsquery('english', 'e-mail');tto_tsvector()to_tsvector('english', body)body@@ALTER TABLE docs ADD COLUMN body_tsv tsvector GENERATED ALWAYS AS (to_tsvector('english', body)) STORED;WHERE body_tsv @@ qts_headline(body, q, '...')bodySTORED