使用 全文索引 替换 like ‘%XX%‘

本文介绍MySQL 5.7.6及以后版本支持的ngram全文检索插件,用于中文分词,适用于MyISAM和InnoDB引擎。文章展示了配置方法、表结构创建、示例数据插入及全文检索示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

其实全文检索在MySQL里面很早就支持了,只不过一直以来只支持英文。缘由是他从来都使用空格来作为分词的分隔符,而对于中文来讲,显然用空格就不合适,需要针对中文语义进行分词。这不,从MySQL 5.7.6开始,MySQL内置了ngram全文检索插件,用来支持中文分词,并且对MyISAM和InnoDB引擎有效。低版本可以使用MySQL中文分词插件SqlJieba/mysqlcft等

查看是否已经配置

SHOW GLOBAL VARIABLES LIKE '%ft_min%';
SHOW GLOBAL VARIABLES LIKE '%ngram_token_size%';

在使用中文检索分词插件ngram之前,先得在MySQL配置文件里面设置他的分词大小,比如,

[mysqld] 
innodb_ft_min_token_size=1
ft_min_word_len=1
ngram_token_size=2 

这里把分词大小设置为2。要记住,分词的SIZE越大,索引的体积就越大,所以要根据自身情况来设置合适的大小。

示例表结构:

CREATE TABLE `articles` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(200) DEFAULT NULL,
  `body` text,
  PRIMARY KEY (`id`),
  FULLTEXT KEY `title` (`title`,`body`) WITH PARSER `ngram` 
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

示例数据,有6行记录。

INSERT INTO `articles`(`id`, `title`, `body`) VALUES (1, '数据库管理', '在本教程中我将向你展示如何管理数据库');
INSERT INTO `articles`(`id`, `title`, `body`) VALUES (2, '数据库应用开发', '学习开发数据库应用程序');
INSERT INTO `articles`(`id`, `title`, `body`) VALUES (3, 'MySQL完全手册', '学习MySQL的一切');
INSERT INTO `articles`(`id`, `title`, `body`) VALUES (4, '数据库与事务处理', '系统的学习数据库的事务概论');
INSERT INTO `articles`(`id`, `title`, `body`) VALUES (5, 'NoSQL精髓', '学习了解各种非结构化数据库');
INSERT INTO `articles`(`id`, `title`, `body`) VALUES (6, 'SQL语言详解', '详细了解如果使用各种SQL');
INSERT INTO `articles`(`id`, `title`, `body`) VALUES (7, 'Test Delete', '测试删除');

显式指定全文检索表源

mysql> SET GLOBAL innodb_ft_aux_table='db_name/articles'; 
Query OK, 0 rows affected (0.00 sec) 

通过系统表,就可以查看到底是怎么划分articles里的数据。当用户对表进行全文检索(查询、插入)时,InnoDB存储引擎会自动读取未完成的文档,然后进行分词操作,再将分词结果放到FTS Index Cache

mysql> SELECT * FROM information_schema.INNODB_FT_INDEX_CACHE LIMIT 20,10; 
+——+————–+————-+———–+——–+———-+ 
| WORD | FIRST_DOC_ID | LAST_DOC_ID | DOC_COUNT | DOC_ID| POSITION | 
+——+————–+————-+———–+——–+———-+ 
| 中我 | 2 | 2 | 1 | 2 | 28 | 
| 习m | 4 | 4 | 1 | 4 | 21 | 
| 习了 | 6 | 6 | 1 | 6 | 16 | 
| 习开 | 3 | 3 | 1 | 3 | 25 | 
| 习数 | 5 | 5 | 1 | 5 | 37 | 
| 了解 | 6 | 7 | 2 | 6 | 19 | 
| 了解 | 6 | 7 | 2 | 7 | 23 | 
| 事务 | 5 | 5 | 1 | 5 | 12 | 
| 事务 | 5 | 5 | 1 | 5 | 40 | 
| 何管 | 2 | 2 | 1 | 2 | 52 | 
+——+————–+————-+———–+——–+———-+ 
10 rows in set (0.00 sec) 

这里可以看到,把分词长度设置为2,所有的数据都只有两个一组。可以看到每个word对应一个DOC_ID和POSITION。此外,还记录了FIRST_DOC_ID、LAST_DOC_ID、DOC_COUNT分别代表该word第一次出现文档的ID,最后一次出现的文档ID,以及该word在多少个文档中存在。 文档中的分词的插入操作是在事务提交时完成,

但是对于删除操作,其在事务提交时,不删除磁盘Auxiliary Table的记录,而只是删除FTS Cache Index记录,对于Auxiliary Table中被删除的记录,存储引擎会记录其FTS DOCUMENT ID ,并将其保存在DELETE auxiliary table中,在设置参数innodb_ft_aux_table后,用户可以访问information_schema架构下的表INNODB_FT_DELETED来观察删除的FTS Document ID只有当OPTIMIZE TABLE发生的时候才会被清除掉。这个表只有一个DOC__ID列,是指向innodb_ft_index_table这张表

SET GLOBAL innodb_optimize_fulltext_only=ON;

OPTIMIZE TABLE articles;

SELECT * FROM information_schema.`INNODB_FT_INDEX_TABLE`;

若此时执行下面的SQL语句,会删除FTS_DOC_ID为7的文档

DELETE FROM articles WHERE id=7

InnoDB存储引擎并不会直接删除索引中对应的记录,而是将删除的文档ID插入到DELETED表

SELECT * FROM information_schema.`INNODB_FT_DELETED`;

SELECT * FROM information_schema.INNODB_FT_INDEX_CACHE where DOC_ID=7;

使用全文索引的格式:

MATCH (columnName) AGAINST ('string')

多个条件string空格分隔

查询title或body包含信息

一、自然语言模式下检索: 

1、得到符合条件的个数

mysql>SELECT COUNT(*) FROM articles WHERE MATCH (title,body) AGAINST ('数据库' IN NATURAL LANGUAGE MODE); 
+———-+ 
| COUNT(*) | 
+———-+ 
| 4 | 
+———-+ 
1 row in set (0.05 sec) 

2、得到匹配的比率

mysql>SELECT id, MATCH (title,body) AGAINST ('数据库' IN NATURAL LANGUAGE MODE) AS score FROM articles; 
+—-+———————-+ 
| id| score | 
+—-+———————-+ 
| 1 | 0.12403252720832825 | 
| 2 | 0.12403252720832825 | 
| 3 | 0 | 
| 4 | 0.12403252720832825 | 
| 5 | 0.062016263604164124| 
| 6 | 0 | 
+—-+———————-+ 
6 rows in set (0.00 sec) 

二、布尔模式下搜索,这个就相对于自然模式搜索来的复杂些: 

1、匹配既有管理又有数据库的记录, 类似sql的AND

mysql> SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('+数据库 +管理' IN BOOLEAN MODE); 
+—-+————+————————————–+ 
| id| title | body | 
+—-+————+————————————–+ 
| 1 | 数据库管理 | 在本教程中我将向你展示如何管理数据库 | 
+—-+————+————————————–+ 
1 row in set (0.00 sec) 

2、匹配有数据库,但是没有管理的记录

mysql> SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('+数据库 -管理' IN BOOLEAN MODE); 
+—-+——————+—————————-+ 
| id| title | body | 
+—-+——————+—————————-+ 
| 2 | 数据库应用开发 | 学习开发数据库应用程序 | 
| 4 | 数据库与事务处理 | 系统的学习数据库的事务概论 | 
| 5 | NoSQL 精髓 | 学习了解各种非结构化数据库 | 
+—-+——————+—————————-+ 
3 rows in set (0.00 sec) 

3、匹配MySQL,但是把数据库的相关性降低

mysql> SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('>数据库 +MySQL' INBOOLEAN MODE); 
+—-+—————+—————–+ 
| id| title | body | 
+—-+—————+—————–+ 
| 3 | MySQL完全手册 |学习MySQL的一切 | 
+—-+—————+—————–+ 
1 row in set (0.00 sec) 

4、匹配有管理或者有数据库的记录

mysql> SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('数据库 管理' IN BOOLEAN MODE); 

三、查询扩展模式,比如要搜索数据库,那么MySQL,oracle,DB2也都将会被搜索到

mysql> SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('数据库' WITH QUERY EXPANSION); 
+—-+——————+————————————–+ 
| id| title | body | 
+—-+——————+————————————–+ 
| 1 | 数据库管理 | 在本教程中我将向你展示如何管理数据库 | 
| 4 | 数据库与事务处理 | 系统的学习数据库的事务概论 | 
| 2 | 数据库应用开发 | 学习开发数据库应用程序 | 
| 5 | NoSQL 精髓 | 学习了解各种非结构化数据库 | 
| 6 | SQL 语言详解 | 详细了解如果使用各种SQL | 
| 3 | MySQL完全手册 | 学习MySQL的一切 | 
+—-+——————+————————————–+ 
6 rows in set (0.01 sec) 

当然,我这里只是功能演示,更多的性能测试,大家有兴趣可以进行详细测试。由于N-grm是中文检索常用的分词算法,已经在互联网大量使用,这次集成到MySQL中,想必效果上不会有太大的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值