MySQL使用全文索引替换 like '%XX%' 查询


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

例如:
删除没有指定分词算法的全文索引:
alter table nsy_product.product_custom_report drop index idx_custom_product_sku;
alter table nsy_product.product_custom_report drop index idx_embryo_product_sku;
修改后指定分词算法的全文索引:
alter table nsy_product.product_custom_report add FULLTEXT INDEX `idx_custom_product_sku` (`custom_product_sku`) with parser ngram;
alter table nsy_product.product_custom_report add FULLTEXT INDEX `idx_embryo_product_sku` (`embryo_product_sku`) with parser ngram;

注意,如果是阿里云的RDS,需要用以下的方式创建,不需要指定with parser ngram,
格式如下:
alter table nsy_product.product_custom_report add FULLTEXT key `idx_custom_product_sku` (`custom_product_sku`) ;
alter table nsy_product.product_custom_report add FULLTEXT key `idx_embryo_product_sku` (`embryo_product_sku`)  ;


查看是否已经配置
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;


或者:
alter table articles add fulltext index `title` (`title`,`body`)  with parser ngram; 


示例数据,有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;
   +——+————�C+————-+———�C+——�C+———-+
  | WORD | FIRST_DOC_ID | LAST_DOC_ID | DOC_COUNT | DOC_ID| POSITION |
  +——+————�C+————-+———�C+——�C+———-+
  | 中我 | 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 |
  +——+————�C+————-+———�C+——�C+———-+
 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包含信息
一、自然语言模式下检索:
 得到符合条件的个数
 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);
 +—-+————+————————————�C+
 | id| title | body |
 +—-+————+————————————�C+
| 1 | 数据库管理 | 在本教程中我将向你展示如何管理数据库 |
 +—-+————+————————————�C+
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);
+—-+—————+—————�C+
 | id| title | body |
 +—-+—————+—————�C+
 | 3 | MySQL完全手册 |学习MySQL的一切 |
+—-+—————+—————�C+
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);
+—-+——————+————————————�C+
| id| title | body |
+—-+——————+————————————�C+
 | 1 | 数据库管理 | 在本教程中我将向你展示如何管理数据库 |
 | 4 | 数据库与事务处理 | 系统的学习数据库的事务概论 |
 | 2 | 数据库应用开发 | 学习开发数据库应用程序 |
| 5 | NoSQL 精髓 | 学习了解各种非结构化数据库 |
 | 6 | SQL 语言详解 | 详细了解如果使用各种SQL |
 | 3 | MySQL完全手册 | 学习MySQL的一切 |
+—-+——————+————————————�C+
 6 rows in set (0.01 sec)

分割线
感谢打赏
江西数库信息技术有限公司
YWSOS.COM 平台代运维解决方案
 评论
 发表评论
姓   名:

Powered by AKCMS