全文索引
MySQL全文索引:FULLTEXT索引创建、自然语言模式、布尔模式、n-gram解析器与中文分词
1. 全文索引概述
MySQL 全文索引(FULLTEXT Index)支持对文本内容进行全文检索,InnoDB 和 MyISAM 均支持。
2. 创建全文索引
-- 创建表时定义
CREATE TABLE articles (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(200),
content TEXT,
FULLTEXT INDEX ft_title_content (title, content)
) ENGINE = InnoDB;
-- 在已有表上创建
ALTER TABLE articles ADD FULLTEXT INDEX ft_content (content);
-- 使用 n-gram 解析器(支持中文)
ALTER TABLE articles ADD FULLTEXT INDEX ft_content (content)
WITH PARSER ngram;
3. 搜索模式
3.1 自然语言模式
-- 默认模式,按相关性排序
SELECT * FROM articles
WHERE MATCH(title, content) AGAINST('数据库 索引');
-- 获取相关性分数
SELECT *, MATCH(title, content) AGAINST('数据库 索引') AS score
FROM articles
WHERE MATCH(title, content) AGAINST('数据库 索引')
ORDER BY score DESC;
3.2 布尔模式
-- 支持操作符
SELECT * FROM articles
WHERE MATCH(title, content) AGAINST('+MySQL -索引' IN BOOLEAN MODE);
-- 操作符说明:
-- + 必须包含
-- - 必须不包含
-- 无 可选,包含则提高相关性
-- > 提高权重
-- < 降低权重
-- * 通配符(前缀匹配)
-- " 短语匹配
-- () 分组
-- ~ 取反(降低相关性)
-- 短语匹配
SELECT * FROM articles
WHERE MATCH(content) AGAINST('"MySQL索引优化"' IN BOOLEAN MODE);
-- 前缀匹配
SELECT * FROM articles
WHERE MATCH(content) AGAINST('数据*' IN BOOLEAN MODE);
3.3 查询扩展模式
-- 两阶段搜索:先搜关键词,再用结果中的词扩展搜索
SELECT * FROM articles
WHERE MATCH(content) AGAINST('数据库' WITH QUERY EXPANSION);
4. n-gram 解析器
-- 中文分词支持
-- ngram_token_size = 2(默认,双字分词)
CREATE TABLE chinese_articles (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(200),
content TEXT,
FULLTEXT INDEX ft_content (content) WITH PARSER ngram
) ENGINE = InnoDB;
-- 搜索中文
SELECT * FROM chinese_articles
WHERE MATCH(content) AGAINST('数据库' IN NATURAL LANGUAGE MODE);
5. 限制与注意事项
-- 最小词长度:innodb_ft_min_token_size = 3(默认)
-- ngram 时由 ngram_token_size 决定
-- 全文索引不支持前缀索引
-- 全文索引列不支持排序
-- 全文索引不支持 % 通配符
-- 建议在数据导入完成后再创建全文索引
全文索引创建
基本写法:建表时创建全文索引
CREATE TABLE <表名> (... FULLTEXT KEY <索引名>(<列1>[, <列2>...])) [WITH PARSER <解析器>];
-- 创建带中文全文索引的文章表(需 ngram 解析器支持中文)
CREATE TABLE articles (
id BIGINT PRIMARY KEY,
title VARCHAR(200),
body TEXT,
FULLTEXT KEY ft_title_body (title, body) WITH PARSER ngram
) ENGINE = InnoDB;
基本写法:为已有表添加全文索引
CREATE FULLTEXT INDEX <索引名> ON <表名>(<列>[, <列>...]) [WITH PARSER <解析器>];
-- 为 body 列添加全文索引
CREATE FULLTEXT INDEX ft_body ON articles(body) WITH PARSER ngram;
基本写法:ALTER 添加全文索引
ALTER TABLE <表名> ADD FULLTEXT INDEX <索引名>(<列>[, <列>...]) [WITH PARSER <解析器>];
-- 通过 ALTER 添加复合全文索引
ALTER TABLE articles
ADD FULLTEXT INDEX ft_title_body (title, body) WITH PARSER ngram;
全文搜索查询
基本写法:MATCH … AGAINST 自然语言搜索
SELECT ... WHERE MATCH(<列>) AGAINST('<关键词>')
-- 自然语言模式搜索(默认)
SELECT id, title, MATCH(title, body) AGAINST('数据库') AS relevance
FROM articles
WHERE MATCH(title, body) AGAINST('数据库')
ORDER BY relevance DESC;
基本写法:布尔模式搜索
SELECT ... WHERE MATCH(<列>) AGAINST('<表达式>' IN BOOLEAN MODE)
-- 布尔模式:+必须包含,-排除,*通配
SELECT * FROM articles
WHERE MATCH(title, body) AGAINST('+MySQL -Oracle' IN BOOLEAN MODE);
-- 包含任意一个词
SELECT * FROM articles
WHERE MATCH(title, body) AGAINST('MySQL PostgreSQL' IN BOOLEAN MODE);
-- 前缀匹配
SELECT * FROM articles
WHERE MATCH(title, body) AGAINST('data*' IN BOOLEAN MODE);
基本写法:查询扩展模式
SELECT ... WHERE MATCH(<列>) AGAINST('<关键词>' WITH QUERY EXPANSION)
-- 查询扩展:自动扩展相关词进行二次搜索(召回率高但精度低)
SELECT * FROM articles
WHERE MATCH(title, body) AGAINST('database' WITH QUERY EXPANSION);
ngram 中文解析器
基本写法:ngram 分词配置
SET GLOBAL ngram_token_size = <数值>;
-- 查看 ngram 分词长度(默认 2,需在配置文件设置)
SHOW VARIABLES LIKE 'ngram_token_size';
基本写法:配置文件设置 ngram
ngram_token_size = 2
# my.cnf 中设置 ngram 分词长度(重启生效)
[mysqld]
ngram_token_size = 2
基本写法:ngram 布尔搜索中文
SELECT ... WHERE MATCH(<列>) AGAINST('<中文词>' IN BOOLEAN MODE)
-- ngram 模式下中文搜索("数据库"会被切分为"数据""据库")
SELECT id, title FROM articles
WHERE MATCH(title, body) AGAINST('+数据 +据库' IN BOOLEAN MODE);
索引维护
基本写法:查看全文索引
SHOW INDEX FROM <表名> WHERE Index_type = 'FULLTEXT';
-- 查看表的全文索引
SHOW INDEX FROM articles WHERE Index_type = 'FULLTEXT';
基本写法:删除全文索引
ALTER TABLE <表名> DROP INDEX <索引名>;
-- 删除全文索引
ALTER TABLE articles DROP INDEX ft_title_body;
-- 或使用 DROP INDEX
DROP INDEX ft_body ON articles;
基本写法:重建全文索引
ALTER TABLE <表名> DROP INDEX <索引名>, ADD FULLTEXT INDEX <索引名>(<列>) WITH PARSER <解析器>;
-- 重建全文索引(数据变更后统计信息更新)
ALTER TABLE articles
DROP INDEX ft_body,
ADD FULLTEXT INDEX ft_body (body) WITH PARSER ngram;
布尔模式运算符
基本写法:运算符速查
AGAINST('<+包含> <-排除> <可选> "<短语>" <前缀>*' IN BOOLEAN MODE)
-- + 包含该词
MATCH(body) AGAINST('+MySQL' IN BOOLEAN MODE)
-- - 排除该词
MATCH(body) AGAINST('-Oracle' IN BOOLEAN MODE)
-- 无符号:该词可选,相关性更高
MATCH(body) AGAINST('MySQL 性能' IN BOOLEAN MODE)
-- "短语":完整匹配短语
MATCH(body) AGAINST('"full text search"' IN BOOLEAN MODE)
-- * 前缀通配(必须 3 字符以上)
MATCH(body) AGAINST('opti*' IN BOOLEAN MODE)
-- () 分组
MATCH(body) AGAINST('+MySQL +(优化 调优)' IN BOOLEAN MODE)
-- ~ 词之间距离(接近度)
MATCH(body) AGAINST('MySQL~性能' IN BOOLEAN MODE)
基本写法:相关性排序
SELECT MATCH(<列>) AGAINST('<词>') AS <相关度> FROM <表> ORDER BY <相关度> DESC
-- 返回相关性分数并排序
SELECT
id,
title,
MATCH(title, body) AGAINST('数据库 优化') AS score
FROM articles
WHERE MATCH(title, body) AGAINST('数据库 优化' IN BOOLEAN MODE)
ORDER BY score DESC
LIMIT 20;