ngram

Exisi 2023-03-26 18:24:12
Categories: Tags:
  • 内置的MySQL全文解析器使用单词之间的空格作为分隔符,以确定单词的开始和结束位置,这在处理不使用单词分隔符的表意语言时是一个限制。为了解决这个问题,MySQL 提供了一个支持中文、日文和韩文(CJK)ngram全文解析器,且对 MyISAM InnoDB 引擎有效

 

  • 在使用中文检索分词插件 ngram 之前,先得在MySQL配置文件里面设置他的分词大小(默认是2

 

  • 临时设置

mysqld --ngram_token_size=2

 

  • 配置文件

[mysqld]

ngram_token_size=21~10

 

  • 在全文索引中,n-gram就是一段文字里面连续的n个字的序列。例如,用n-gram来对”信息系统”来进行分词,得到的结果如下:

 

序号

分词大小

分词结果

1

N=1

‘信’, ‘息’, ‘系’, ‘统’

2

N=2

‘信息’, ‘息系’, ‘系统’

3

N=3

‘信息系’, ‘息系统’

4

N=4

‘信息系统’

  • 分词的SIZE越小,索引的体积就越大,所以要根据自身情况来设置合适的大小

 

  • 因为有了 ngram_token_size,所以 innodb_ft_min_token_size innodb_ft_max_token_size 将不适用于 n-gram

 

  • ngram 解析器在解析时消除了空格。例如:“ab cd”被解析为“ab”“cd”“a bc”被解析为“bc”

 

 

 

ngram 解析器的使用

  • ngram是默认加载到MySQL中并可以直接使用的。

语法

WITH PARSER ngram

 

  • 我们只需要在创建全文索引时同时启用 ngram 既可。

示例

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)

示例

ALTER TABLE articles ADD FULLTEXT INDEX ngram_idx(title) WITH PARSER ngram;

示例

CREATE FULLTEXT INDEX ngram_idx ON articles(title) WITH PARSER ngram;

 

 

 

ngram 查询处理

  • 在自然语言模式(NATURAL LANGUAGE MODE)下,文本的查询被转换为 ngram分词查询的并集。

示例

INSERT INTO articles (title)

VALUES ('信息系统'), ('信息 系统'), ('信息的系统'), ('信息'), ('系统'), ('息系');

 

Query OK, 6 rows affected (0.01 sec)
Records: 6  Duplicates: 0  Warnings: 0

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),文本查询被转化为 ngram 分词的短语查询。

示例

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 小,那么查询结果将返回在全文索引中所有以这个词作为前缀的 ngram 的词,比如 n=2 , 搜索 "a*" 会返回所有 ngram token 中以 "a" 开头的行

示例

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),通配符则被忽略。比如 n=2 , "abc*" 通配符搜索会被转换为 "ab bc"

示例

SELECT * FROM articles

WHERE MATCH (title) AGAINST ('信息系*' IN BOOLEAN MODE);

 

运行结果如下:

+------------------+--------------+
| FTS_DOC_ID
 | title            |
+------------------+--------------+
|      
                1 | 信息系统     |
+------------------+--------------+
1 row in set (0.00 sec)

phrase search 会被转换为 ngram phrase search。比如搜索短语 "abc" 会被转换为 "ab bc", 返回包含 "abc" "ab bc" 的文档。搜索短语 "abc def" 会被转换为 "ab bc de ef", 返回包含 "abc def" "ab bc de ef" 的文档。文档包含 "abcdef" 的却不会返回

 

 

 

ngram 停止词处理

  • 内置MySQL全文解析器将单词与 stopword 列表中的条目进行比较。如果其中某个单词等于停止词列表中的某个条目,则该单词将从索引中排除。

 

  • 通常,对于一个新的词,我们会查找 stopwords 表,看是否有匹配的词。如果有,这个词就不会加入到全文索引中。但是在n-gram中,我们会查找 stopwords 表,看是否包含里面的词。这样处理的原因是,在中日韩的文本中,有很多没有意义的字符,词语和标点符号。

 

  • 例如,假设 ngram_token_size=2,包含“ab”的文档将被解析为“ab”。如果逗号()被定义为停止字,则“ab”都将从索引中排除,因为它们包含逗号。

 

  • 我们可以通过查询INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHEINFORMATION_SCHEMA.INNODB_FT_TABLE_TABLE来查询哪些词在全文索引里面。这是一个非常有用的调试工具。

 

  • 如果我们发现一个包含某个词的文档,没有如我们所期望的那样出现在查询结果中,那么这个词可能是因为某些原因不在全文索引里面。比如,它含有 stopword,或者它的大小小于 ngram_token_size 等等。这个时候我们就可以通过查询这两个表来确认。

示例

INSERT INTO articles (title) VALUES ('信息系统');

Query OK, 1 row affected (0.01 sec)
 

SET GLOBAL innodb_ft_aux_table="test/articles";
Query OK, 0 rows affected (0.00 sec)

 

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)

  • 长度大于 ngram_token_size 的停止词将被忽略

 

  • 默认情况下,ngram解析器使用默认的stopword列表,其中包含英文stopword的列表。对于适用于中文、日语或韩语的关键词列表,您必须创建自己的关键词列表。

 

 

来自 <https://dev.mysql.com/doc/refman/8.0/en/fulltext-search-ngram.html>