Mysql使用全文索引实现简易搜索及ngram中文分词配置

栗子
栗子
发布时间:2026-10-16| 5人浏览过
原创

面对项目中的关键词搜索需求,在服务器资源受限且无部署ElasticSearch条件的情况下,可利用MySQL自带的全文索引功能快速实现简易搜索引擎。本文基于MySQL 8.0及InnoDB引擎,详解如何使用ngram解析器处理中文分词,包括索引创建、自然语言与布尔检索模式的语法应用,以及通过实测数据证明其性能优于传统LIKE模糊查询。

结果与准备

当需要实现聊天记录等文本的关键词检索,但缺乏额外资源部署分布式搜索引擎时,MySQL全文索引是一个轻量级解决方案。该方案基于倒排索引原理,能高效定位包含特定关键词的文档。本教程针对MySQL 5.7.6及以上版本,特别是支持内置ngram全文解析器的版本,用于解决中文分词问题。

ngram 中文分词原理

ngram 是将文本切分为连续 n 个字符序列的方法。例如对“你好靓仔”进行分词:

n=1: '你', '好', '靓', '仔'
n=2: '你好', '好靓', '靓仔'
n=3: '你好靓', '好靓仔'
n=4: '你好靓仔'

MySQL通过全局变量 ngram_token_size 控制分词大小,取值范围1-10,默认值为2。若需支持单字搜索,必须将值设为1,否则单字搜索将无法返回结果。通常推荐保持默认的2,因为中文词汇多为双字词。

查看当前配置:

show variables like 'ngram_token_size'

设置 ngram_token_size 有两种方式:

  1. 启动参数指定:运行 mysqld --ngram_token_size=2
  2. 修改配置文件:在 my.ini 或 my.cnf 中添加 ngram_token_size=2,重启服务生效。

创建全文索引

可在InnoDB引擎表中为字符串列添加FULLTEXT索引。以下提供三种创建方式:

第1步:建表时直接创建

目的:在设计表结构时同步建立索引,适合新表开发。

CREATE TABLE `article` (
  `id` bigint NOT NULL,
  `url` varchar(1024) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `title` varchar(256) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `source` varchar(32) COLLATE utf8mb4_general_ci DEFAULT '',
  `keywords` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `publish_time` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  FULLTEXT KEY `title_index` (`title`) WITH PARSER `ngram`
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

第2步:使用 ALTER TABLE 添加

目的:为已存在但未建索引的表补充全文索引。

ALTER TABLE article ADD FULLTEXT INDEX title_index(title) WITH PARSER ngram;

第3步:使用 CREATE INDEX 添加

目的:等同于ALTER TABLE方式的另一种语法标准。

CREATE FULLTEXT INDEX title_index ON article (title) WITH PARSER ngram;

检索操作详解

MySQL全文索引主要支持两种检索模式:自然语言模式和布尔模式。

1. 自然语言检索 (NATURAL LANGUAGE MODE)

这是默认检索模式。它自动根据词库分词,不支持复杂逻辑操作符,结果按匹配度降序排列。

-- 显式指定模式
SELECT * FROM article WHERE MATCH(title) AGAINST ('北京旅游' IN NATURAL LANGUAGE MODE);

-- 隐式默认模式(同上)
SELECT * FROM article WHERE MATCH(title) AGAINST ('北京旅游');

在此模式下,“北京旅游”会被拆分为“北京”和“旅游”,只要标题包含其中任一关键词即可匹配。

如需查看每条结果的匹配得分(浮点数),可加入计算字段:

SELECT *, MATCH(title) AGAINST ('北京旅游') AS score 
FROM article 
WHERE MATCH(title) AGAINST ('北京旅游' IN NATURAL LANGUAGE MODE);

2. 布尔检索 (BOOLEAN MODE)

布尔模式允许使用操作符精确控制关键词的存在与否及权重,适合复杂查询。

-- 包含“约会”或“攻略”(空格默认为OR)
SELECT * FROM article WHERE MATCH(title) AGAINST ('约会 攻略' IN BOOLEAN MODE);

常用操作符示例:

'+约会 +攻略'    -> 必须同时包含两者
'+约会 攻略'     -> 必须包含约会,若包含攻略则加分
'+约会 -攻略'    -> 必须包含约会,且不包含攻略
'+约会 ~攻略'    -> 必须包含约会,若包含攻略会降低相关度排名
'+约会 +(>攻略 <技巧)' -> 必须包含约会和(攻略或技巧),约会+攻略的相关度高于约会+技巧
'约会*'          -> 前缀匹配,如“约会”开头的词
'"约会攻略"'     -> 短语匹配,类似 LIKE '%约会攻略%'
-- 必须包含“约会”,可含“攻略”
SELECT * FROM article WHERE MATCH(title) AGAINST ('+约会 攻略' IN BOOLEAN MODE);

性能对比与结论

相较于传统的 LIKE '%keyword%' 模糊查询,全文索引具有显著优势:

  • 语义理解:全文索引会进行分词,而LIKE仅是字符匹配。
  • 可配置性:支持自定义最小/最大词长及忽略词。
  • 相关性排序:返回匹配得分,便于结果优化。
  • 性能极高:基于倒排索引,避免了全表扫描。

在约50万数据的测试环境中:

LIKE 查询耗时:

SELECT * FROM article WHERE title LIKE '%北京%';

全文索引查询耗时:

SELECT * FROM article WHERE MATCH(title) AGAINST ('北京' IN BOOLEAN MODE);

结果显示,全文索引查询速度约为0.094秒,而LIKE查询约为1.536秒,全文索引性能提升约16倍。虽然全文索引会带来一定的DML写入开销和存储空间消耗,但在数据量适中(非海量)的场景下,它是比部署ES更经济高效的搜索方案。

以上就是MySQL使用全文索引和ngram解析器实现简易版中文搜索引擎的详细内容,更多关于MySQL全文搜索配置与优化的资料请关注本站其它相关文章!
相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。