GBase 8c 做中文检索,别只剩 LIKE 在硬扫
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');
查询时使用 tsquery 与 tsvector 匹配,而不是拼接 %关键字%。
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/
评论
热门帖子
- 12025-12-01浏览数:183215
- 22023-05-09浏览数:25986
- 42023-09-25浏览数:19638
- 52020-05-11浏览数:18269