ngram

isixe 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=2(1~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,包含“a,b”的文档将被解析为“a,”和“,b”。如果逗号(“,”)被定义为停止字,则“a,”和“,b”都将从索引中排除,因为它们包含逗号。

 

  • 我们可以通过查询INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE和INFORMATION_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>