InnoDB全文索引:N-gram Parser

InnoDB默認的全文索引parser很是合適於Latin,由於Latin是經過空格來分詞的。但對於像中文,日文和韓文來講,沒有這樣的分隔符。一個詞能夠由多個字來組成,因此咱們須要用不一樣的方式來處理。在MySQL 5.7.6中咱們能使用一個新的全文索引插件來處理它們:n-gram parser.html

什麼是N-gram?mysql

在全文索引中,n-gram就是一段文字裏面連續的n個字的序列。例如,用n-gram來對」信息系統」來進行分詞,獲得的結果以下:sql

N-gram 例子oracle

 

1工具

2sqlserver

3插件

4調試

N=1 : '信', '息', '系', '統';server

N=2 : '信息', '息系', '系統';htm

N=3 : '信息系', '息系統';

N=4 : '信息系統';

 如何在InnoDB中使用N-gram Parser?

N-gram parser是默認加載到MySQL中並能夠直接使用的。咱們只須要在DDL中建立全文索引時使用WITH PARSER ngram。好比,下面的SQL語句在MySQL 5.7.6及更高版本上能夠運行。

N-gram DDL示例

 

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的詞,速度會更快,可是查詢比它更長的詞或短語,則會變慢。

N-gram分詞處理

N-gram parser和系統默認的全文索引parser有以下不一樣點:

  1. 詞大小檢查:由於有了ngram_token_size,因此innodb_ft_min_token_sizeinnodb_ft_max_token_size將不適用於n-gram。
  2. 無用詞(stopword)處理:一般,對於一個新的詞,咱們會查找stopwords表,看是否有匹配的詞。若是有,這個詞就不會加入到全文索引中。可是在n-gram中,咱們會查找stopwords表,看是否包含裏面的詞。這樣處理的緣由是,在中日韓的文本中,有不少沒有意義的字符,詞語和標點符號。好比,若是咱們把‘的’加入到stopwords表中,那麼對於句子‘信息的系統’,在默認狀況下咱們分詞結果爲‘信息’,‘系統’。其中‘息的’和‘的系’被過濾掉了。

咱們能夠經過查詢INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHEINFORMATION_SCHEMA.INNODB_FT_TABLE_TABLE來查詢哪些詞在全文索引裏面。這是一個很是有用的調試工具。若是咱們發現一個包含某個詞的文檔,沒有如咱們所指望的那樣出如今查詢結果中,那麼這個詞多是由於某些緣由不在全文索引裏面。好比,它含有stopword,或者它的大小小於ngram_token_size等等。這個時候咱們就能夠經過查詢這兩個表來確認。下面是一個簡單的例子:

簡單的調試示例

 

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)

  • 在天然語言模式(NATURAL LANGUAGE MODE)下,文本的查詢被轉換爲n-gram分詞查詢的並集。例如,(‘信息系統’)轉換爲(‘信息 息系 系統’)。下面一個例子:

    天然語言模式示例

     

    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)

  • 在布爾模式(BOOLEAN MODE),文本查詢被轉化爲n-gram分詞的短語查詢。例如,(‘信息系統’)轉換爲(「‘信息 息系 系統'」)。

    布爾模式示例

     

    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)

  • 若是前綴的長度比ngram_token_size小,那麼查詢結果將返回在全文索引中全部以這個詞做爲前綴的n-gram的詞。

    通配符查詢示例-1

     

    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)

  • 若是前綴的長度大於等於ngam_token_size,那麼這個查詢則轉換爲一個短語(phrase search),通配符則被忽略。例如,(‘信息*’)轉換爲(‘」信息」‘),(‘信息系*’)轉換爲(‘」信息 息系」‘)。

    通配符查詢示例-2

     

    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)

  • 短語查詢則被轉換爲n-gram分詞的短語查詢。好比,(‘信息系統’)轉換爲(‘」信息 息系 系統」‘)。

    短語查詢示例

     

    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!

相關文章
相關標籤/搜索