GBase 8c
其他
文章

GBase 8c 做中文检索,别只剩 LIKE 在硬扫

发表于2026-05-14 09:30:0530次浏览1个评论

GBase 8c 做中文检索,别只剩 LIKE 在硬扫

我最近看 GBase 8c 全文检索资料时,比较有感触的一点是:很多业务系统已经存了大量中文文本,但查询方式还停留在 LIKE '%关键字%'。数据量小的时候能忍,表一大、字段一长、组合条件一多,LIKE 就很容易变成全表扫描。真正落到检索类需求时,中文分词、全文索引、搜索表达式这些能力要尽早纳入设计。

GBase 8c 提供全文检索能力,并且包含适合中文和中英混合场景的解析器。对日志摘要、工单内容、客户反馈、知识库标题、商品描述这类字段,如果还按普通字符串模糊匹配处理,后期性能和相关性都会比较难控。

LIKE 适合简单匹配,不适合检索系统

LIKE 不是不能用,而是边界要清楚。

查询方式 适合场景 不适合场景
col LIKE 'abc%' 前缀匹配、编码类字段 自由文本检索
col LIKE '%abc%' 小表临时查询 大文本字段高频查询
正则匹配 少量复杂规则筛选 高并发搜索入口
全文检索 文档、标题、描述、工单内容 需要精确逐字节匹配的字段

中文文本还有一个特点:词与词之间没有天然空格。英文场景按空格切词就能解决一部分问题,中文场景如果不做专门解析,很多搜索体验会很别扭。比如用户搜“数据库性能”,系统到底应该匹配“数据库”“性能”,还是只匹配完整连续字符串,这需要检索方案提前定义。

先把文本列分层

我自己做设计时,会先把文本列分成几类,不会所有字段都上全文索引。

文本类型 示例 推荐处理
编码、编号 订单号、客户号 B-tree 或普通等值/前缀匹配
短标题 工单标题、知识标题 可考虑全文索引
长正文 反馈内容、说明文本 适合全文检索
状态枚举 已完成、处理中 普通字段,不需要全文
JSON 或拼接文本 扩展属性 先治理结构,再考虑检索

如果把所有字段都拼成一个大文本做搜索,初期很省事,但后面相关性排序、权限过滤、字段权重都会变得难处理。我更倾向于明确哪些字段参与检索,并保留原始结构。

一个工单检索的例子

假设有一张工单表,用户经常按标题和内容搜索中文关键词。

CREATE TABLE app_ticket.ticket_info (
    ticket_id      bigint PRIMARY KEY,
    title          text,
    content        text,
    ticket_status  varchar(32),
    created_at     timestamp,
    search_doc     tsvector
);

可以把标题和正文转换成全文检索向量。标题通常权重更高,正文权重稍低。实际项目里权重设计可以更细,这里只保留核心思路。

UPDATE app_ticket.ticket_info
SET search_doc =
    setweight(to_tsvector('ngram', coalesce(title, '')), 'A') ||
    setweight(to_tsvector('ngram', coalesce(content, '')), 'B');

查询时使用 tsquerytsvector 匹配,而不是拼接 %关键字%

SELECT
    ticket_id,
    title,
    ticket_status,
    created_at
FROM app_ticket.ticket_info
WHERE search_doc @@ plainto_tsquery('ngram', '数据库 性能')
  AND ticket_status <> 'DELETED'
ORDER BY created_at DESC
LIMIT 20;

这里用 coalesce 是为了避免某个字段为 NULL 后影响整体表达式。GBase 8c 文本检索资料里也提醒过类似处理思路,中文场景尤其容易遇到部分字段为空的情况。

全文索引要配合更新策略

如果检索字段经常更新,search_doc 也要同步维护。常见方式有三种。

方式 优点 风险
查询时动态 to_tsvector 不用维护冗余列 大表查询成本高
写入时应用同步生成 逻辑可控 应用和数据库规则容易不一致
数据库触发器维护 规则集中 高频写入时要评估开销

我更倾向于把 search_doc 作为一列存下来,并在写入或更新时维护。这样搜索时不用反复解析长文本。

-- 更新单条工单时同步刷新检索向量
UPDATE app_ticket.ticket_info
SET title = '数据库响应变慢',
    content = '业务高峰期查询延迟升高,需要排查执行计划和等待事件',
    search_doc =
        setweight(to_tsvector('ngram', coalesce('数据库响应变慢', '')), 'A') ||
        setweight(to_tsvector('ngram', coalesce('业务高峰期查询延迟升高,需要排查执行计划和等待事件', '')), 'B')
WHERE ticket_id = 10001;

如果是批量导入知识库,可以在导入结束后统一刷新 search_doc,再建或维护索引,避免逐行更新带来额外压力。

检索条件不要脱离业务过滤

全文检索只负责“文本匹配”,不应该替代业务条件。比如工单系统里,用户只能看自己部门的数据,或者只能看未删除、已发布的文档。这些过滤条件要和全文条件一起写,而且索引设计也要考虑组合过滤顺序。

SELECT ticket_id, title, created_at
FROM app_ticket.ticket_info
WHERE tenant_id = 'T001'
  AND ticket_status IN ('OPEN', 'PROCESSING', 'CLOSED')
  AND search_doc @@ plainto_tsquery('ngram', '连接超时')
ORDER BY created_at DESC
LIMIT 20;

如果先全文匹配出大量数据,再在应用层过滤权限,既浪费数据库资源,也容易引入越权风险。

中文检索要提前定义预期

中文搜索容易出现“用户以为应该搜到,系统没有搜到”的争议。我的做法是把检索规则提前写清楚。

规则项 需要确认的问题
分词方式 中文、英文、数字、混合文本怎么切
大小写 英文是否忽略大小写
停用词 “的”“了”“和”是否参与检索
同义词 “数据库”和“DB”是否等价
排序 按时间、相关性还是综合排序
高亮 是否需要返回命中片段
权限 检索前过滤还是检索后过滤

GBase 8c 提供能力是一部分,业务体验还要靠规则落地。尤其是知识库和客服检索,相关性排序可能比单纯命中更重要。标题命中、正文命中、近期文档、已验证文档,可以设置不同权重。

从 LIKE 迁到全文检索的处理顺序

我一般不会一次性把所有 LIKE 改掉,而是先挑高频、慢、文本字段长的查询下手。

步骤 动作
1 找出高频 LIKE '%xxx%' 查询
2 确认字段类型和文本长度
3 设计参与检索的字段和权重
4 增加 tsvector 列或表达式
5 建索引并刷新历史数据
6 灰度替换查询语句
7 观察命中率、延迟、用户反馈

示例改造前:

SELECT ticket_id, title
FROM app_ticket.ticket_info
WHERE title LIKE '%连接超时%'
   OR content LIKE '%连接超时%'
ORDER BY created_at DESC
LIMIT 20;

示例改造后:

SELECT ticket_id, title
FROM app_ticket.ticket_info
WHERE search_doc @@ plainto_tsquery('ngram', '连接超时')
ORDER BY created_at DESC
LIMIT 20;

两种写法看起来都能返回结果,但执行路径和扩展能力完全不同。LIKE 更像临时筛选,全文检索才更接近搜索入口。

我会特别避开的坑

第一,不把全文检索当成万能模糊匹配。编码、手机号、证件号这类字段更适合精确或前缀查询。

第二,不在查询时反复对大字段 to_tsvector。数据量上来后,这会变成稳定的 CPU 消耗点。

第三,不忽略 NULL 字段。多个文本字段拼接时,coalesce 能避免很多奇怪结果。

第四,不把权限过滤放到应用层最后做。检索语句里就应该带上租户、部门、状态等条件。

第五,不只追求搜得多。搜得准、排序合理、响应稳定,对业务更重要。

GBase 8c 的全文检索能力对中文和中英混合文本是有价值的。我的感受是,只要业务里已经出现“搜索框”,就应该尽早区分普通筛选和全文检索。继续靠 %关键字% 硬扫,短期省事,长期会把性能和体验都拖住。

参考资料

GBase 8c 全文检索 https://www.gbase.cn/docs/gbase-8c/05%20SQL%E5%8F%82%E8%80%83/%E5%85%A8%E6%96%87%E6%A3%80%E7%B4%A2
GBase 8c SQL参考指南 https://www.gbase.cn/docs/gbase-8c/05%20SQL%E5%8F%82%E8%80%83/SQL%E8%AF%AD%E6%B3%95
GBase 8c 文档介绍 https://www.gbase.cn/docs/gbase-8c/%E6%AC%A2%E8%BF%8E/

评论

登录后才可以发表评论
GBase用户47954发表于 3个月前
感谢作者的精彩分享!