MySQL 全文索引失效之谜
现象:
在 MySQL 中存在一张数据量较大的表,由于需要使用模糊查询,即“%xxx%”模式,所以创建了全文索引。该表字段的值如下:圆生园;¥圆园;圆生;生园;…圆生;圆生…;…生园;生园…。然而,当使用“SELECT * FROM my_table WHERE MATCH(column) AGAINST(‘+生园’ IN BOOLEAN MODE);”进行查询时,却无法得到结果。
原因:
究其根本原因,是分号“;”对 N-gram 分词逻辑产生了干扰,使得“生园”未能被正确识别为独立的词汇。通过将分隔符进行替换,并重新构建索引,便可以确保全文索引能够按照预期正常工作。
解决方案:通过停用词表忽略分号
由于字段值无法修改,可以通过将分号;加入停用词表(Stopwords)来强制全文索引忽略分号,从而避免分号干扰分词结果。以下是具体步骤:
步骤 1:创建自定义停用词表
- 新建停用词表:
在数据库中创建一个表,用于存储自定义停用词(如分号;):
CREATE TABLE custom_stopwords (value VARCHAR(30)) ENGINE = INNODB;
INSERT INTO custom_stopwords (value) VALUES (';');
-- 若数据中有其他干扰符号(如¥、…),需一并加入停用词表
INSERT INTO custom_stopwords (value) VALUES ('¥'), ('…');
- 配置MySQL使用该停用词表:
修改MySQL全局配置,指向自定义停用词表:
SET GLOBAL innodb_ft_server_stopword_table = 'your_database_name/custom_stopwords';
注:需确保用户有权限修改全局变量。
步骤 2:重建全文索引
- 删除旧索引:
ALTER TABLE my_table DROP INDEX index_name;
- 创建新索引(忽略分号):
ALTER TABLE my_table
ADD FULLTEXT INDEX index_name(column)
WITH PARSER ngram;
- 强制更新索引缓存:
OPTIMIZE TABLE tm_info;
步骤 3:查询验证
SELECT * FROM my_table WHERE MATCH(column) AGAINST('+"生园"' IN BOOLEAN MODE);
注:+“生园” 表示必须精确包含“生园”。
关键配置说明
配置项 | 作用 | 配置项 |
---|---|---|
custom_stopwords | 存储自定义停用词(如分号) | 需提前创建并插入数据 |
innodb_ft_server_stopword_table | 指定全局停用词表 | 需重启或权限生效 |
ngram_token_size | 控制分词长度(默认2) | 若需匹配单字,可设为1 |