MySQL原生不支持中文分词,需启用ngram插件并设token_size=2,重建索引时指定WITH PARSER ngram;用户输入须白名单清洗后走自然语言模式;title字段在联合索引中权重更高;短词需应用层预处理补位。

MySQL原生不支持中文分词,直接建FULLTEXT索引对中文字段几乎无效——搜“数据库优化”,它不会拆成“数据库”“优化”,而是当一个超长词处理,匹配率极低。必须启用ngram解析器或走外部分词路径。
必须启用ngram插件并配置token_size
MySQL 5.7.6+ 内置ngram插件,专为中文、日文等无空格语言设计。但默认不启用,且ngram_token_size需显式设为2(双字切分)才实用:
- 确认插件已加载:
SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = 'ngram';,若未激活,需在my.cnf中加plugin-load=ngram=libngram.so并重启 - 设置分词粒度:
SET GLOBAL ngram_token_size = 2;(推荐值,1太碎,3以上漏词多) - 重建全文索引:改完参数后,
ALTER TABLE articles DROP INDEX ft_idx, ADD FULLTEXT ft_idx (content) WITH PARSER ngram;——WITH PARSER ngram不能省,否则仍走默认分词器
避免在布尔模式下混用用户输入的原始关键词
AGAINST('用户输入' IN BOOLEAN MODE)看似灵活,但中文场景极易出错:
- 用户搜“MySQL 教程”,若未清洗就拼进SQL,空格会被当操作符,实际执行
AGAINST('MySQL 教程' IN BOOLEAN MODE)会报错ERROR 1064 - 中文里“+”“-”“>”等符号本身是常见字符(如“C++”“A-B测试”),未经过滤直接入参会导致逻辑反转或语法崩溃
- 正确做法:先用白名单正则清理,只留汉字、数字、字母、空格;再用
REPLACE()把连续空格压成单空格;最后套AGAINST('cleaned_string' IN NATURAL LANGUAGE MODE)更安全
组合索引字段顺序影响分词权重
联合全文索引FULLTEXT(title, content)不是简单叠加,title字段的分词结果在倒排索引中默认权重更高:
- 自然语言模式下,相同词出现在
title比出现在content获得更高相关性分数,排序更靠前 - 如果业务强调正文匹配(如法律条文检索),应单独为
content建索引,或用UNION分别查title和content再合并 - 不要为同一字段重复建多个全文索引,InnoDB会拒绝:
ERROR 1214: The used table type doesn't support FULLTEXT indexes(其实是已有索引冲突)
中文短词(2字以下)仍需手动补位
ngram能解决“数据”“库优”这类切分,但对“AI”“Go”“PHP”等西文缩写或单字词(如“云”“端”)依然失效:
-
ft_min_word_len对ngram无效,它只控制传统分词器的最小长度 - 真实方案:应用层预处理,用
jieba或pkuseg分词后,把高频短词(如“AI”“IoT”)额外存入新字段keywords,再对该字段建普通FULLTEXT索引 - 别依赖
OPTIMIZE TABLE修复中文分词效果——它只整理碎片,不重跑分词逻辑;真正生效必须DROP + ADD FULLTEXT ... WITH PARSER ngram
最常被忽略的一点:ngram分词不支持前缀搜索(如“数*”匹配“数据库”),也不支持停用词过滤(“的”“了”全被当有效token)。如果你的业务要求高精度召回,与其硬调参数,不如在应用层做一次轻量级分词+关键词映射,把可控性拿回来。


















