本文来自:http://mysqlserverteam.com/innodb%E5%85%A8%E6%96%87%E7%B4%A2%E5%BC%95%EF%BC%9An-gram-parser/html
InnoDB默认的全文索引parser很是合适于Latin,由于Latin是经过空格来分词的。但对于像中文,日文和韩文来讲,没有这样的分隔符。一个词能够由多个字来组成,因此咱们须要用不一样的方式来处理。在MySQL 5.7.6中咱们能使用一个新的全文索引插件来处理它们:n-gram parser.mysql
什么是N-gram?sql
在全文索引中,n-gram就是一段文字里面连续的n个字的序列。例如,用n-gram来对”信息系统”来进行分词,获得的结果以下:oracle
1
2
3
4
|
N=1 : '信', '息', '系', '统';
N=2 : '信息', '息系', '系统';
N=3 : '信息系', '息系统';
N=4 : '信息系统';
|
如何在InnoDB中使用N-gram Parser?工具
N-gram parser是默认加载到MySQL中并能够直接使用的。咱们只须要在DDL中建立全文索引时使用WITH PARSER ngram。好比,下面的SQL语句在MySQL 5.7.6及更高版本上能够运行。sqlserver
1
2
3
4
5
6
7
8
9
|
mysql > CREATE TABLE articles
(
FTS_DOC_ID BIGINT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
title VARCHAR(100),
FULLTEXT INDEX ngram_idx(title) WITH PARSER ngram
) Engine=InnoDB CHARACTER SET utf8mb4;
Query OK, 0 rows affected (0.06 sec)
mysql> # ALTER TABLE articles ADD FULLTEXT INDEX ngram_idx(title) WITH PARSER ngram;
mysql> # CREATE FULLTEXT INDEX ngram_idx ON articles(title) WITH PARSER ngram;
|
咱们引入了一个新的全局变量叫ngram_token_size。由它来决定n-gram中n的大小,也就是词的大小。它的默认值是2,这个时候,咱们使用的是bigram。它的合法的取值范围是1到10。如今,咱们很天然会想到一个问题:实际应用中应该如何设置ngram_token_size值的大小呢?固然,咱们推荐使用2。可是你也能够经过以下这个简单的规则来能够选择任何合法的值:设置到你但愿能查询到的最小的词的大小。若是你想查询到单个字,那么咱们须要设置为1。 ngram_token_size的值设置的越小,全文索引占用的空间也越小。通常来讲,查询正好等于ngram_token_size的词,速度会更快,可是查询比它更长的词或短语,则会变慢。spa
N-gram分词处理插件
N-gram parser和系统默认的全文索引parser有以下不一样点:调试
咱们能够经过查询INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE和INFORMATION_SCHEMA.INNODB_FT_TABLE_TABLE来查询哪些词在全文索引里面。这是一个很是有用的调试工具。若是咱们发现一个包含某个词的文档,没有如咱们所指望的那样出如今查询结果中,那么这个词多是由于某些缘由不在全文索引里面。好比,它含有stopword,或者它的大小小于ngram_token_size等等。这个时候咱们就能够经过查询这两个表来确认。下面是一个简单的例子:code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
mysql> INSERT INTO articles (title) VALUES ('信息系统');
Query OK, 1 row affected (0.01 sec)
mysql> SET GLOBAL innodb_ft_aux_table="test/articles";
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE;
+--------+--------------+-------------+-----------+--------+----------+
| WORD | FIRST_DOC_ID | LAST_DOC_ID | DOC_COUNT | DOC_ID | POSITION |
+--------+--------------+-------------+-----------+--------+----------+
| 信息 | 1 | 1 | 1 | 1 | 0 |
| 息系 | 1 | 1 | 1 | 1 | 3 |
| 系统 | 1 | 1 | 1 | 1 | 6 |
+--------+--------------+-------------+-----------+--------+----------+
3 rows in set (0.00 sec)
|
N-gram查询处理
文本查询(Text Searches)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
mysql> INSERT INTO articles (title) VALUES ('信息系统'), ('信息 系统'), ('信息的系统'), ('信息'), ('系统'), ('息系');
Query OK, 6 rows affected (0.01 sec)
Records: 6 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM articles WHERE MATCH (title) AGAINST ('信息系统' IN NATURAL LANGUAGE MODE);
+------------+-----------------+
| FTS_DOC_ID | title |
+------------+-----------------+
| 1 | 信息系统 |
| 6 | 息系 |
| 2 | 信息 系统 |
| 3 | 信息的系统 |
| 4 | 信息 |
| 5 | 系统 |
+------------+-----------------+
6 rows in set (0.01 sec)
|
1
2
3
4
5
6
7
|
mysql> SELECT * FROM articles WHERE MATCH(title) AGAINST('信息系统' IN BOOLEAN MODE);
+------------+--------------+
| FTS_DOC_ID | title |
+------------+--------------+
| 1 | 信息系统 |
+------------+--------------+
1 row in set (0.00 sec)
|
通配符查询(Wildcard Searches)
1
2
3
4
5
6
7
8
9
10
|
mysql> SELECT * FROM articles WHERE MATCH (title) AGAINST ('信*' IN BOOLEAN MODE);
+------------+-----------------+
| FTS_DOC_ID | title |
+------------+-----------------+
| 1 | 信息系统 |
| 2 | 信息 系统 |
| 3 | 信息的系统 |
| 4 | 信息 |
+------------+-----------------+
4 rows in set (0.00 sec)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
mysql> SELECT * FROM articles WHERE MATCH (title) AGAINST ('信息*' IN BOOLEAN MODE);
+------------+-----------------+
| FTS_DOC_ID | title |
+------------+-----------------+
| 1 | 信息系统 |
| 2 | 信息 系统 |
| 3 | 信息的系统 |
| 4 | 信息 |
+------------+-----------------+
4 rows in set (0.00 sec)
mysql> SELECT * FROM articles WHERE MATCH (title) AGAINST ('信息系*' IN BOOLEAN MODE);
+------------+--------------+
| FTS_DOC_ID | title |
+------------+--------------+
| 1 | 信息系统 |
+------------+--------------+
1 row in set (0.00 sec)
|
短语查询(Phrase Searches)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
mysql> SELECT * FROM articles WHERE MATCH (title) AGAINST('"信息系统"' IN BOOLEAN MODE);
+------------+--------------+
| FTS_DOC_ID | title |
+------------+--------------+
| 1 | 信息系统 |
+------------+--------------+
1 row in set (0.00 sec)
mysql> SELECT * FROM articles WHERE MATCH (title) AGAINST ('"信息 系统"' IN BOOLEAN MODE);
+------------+---------------+
| FTS_DOC_ID | title |
+------------+---------------+
| 2 | 信息 系统 |
+------------+---------------+
1 row in set (0.01 sec)
|
若是您想了解更多关于InnoDB全文索引的详细内容,能够参考用户手册中InnoDB全文索引的部分,还有Jimmy在Dr. Dobb上的精彩文章。若是您想了解更多关于n-gram的详细内容,则能够参考用户手册中n-gram parser的部分。
咱们很高兴在MySQL 5.7全文索引中加强对中日韩文的支持,这也是咱们工做中很重要的部分,但愿这个功能对你们有帮助。若是您有任何问题,能够在本blog中进行评论,提交一个服务需求,或者提交一个bug报告。
最后,感谢您使用MySQL!