MySQL全文索引(二)ngram全文解析器

TrumanWong
11/27/2024
TrumanWong

默认的MySQL全文解析器采用空格作为分隔符来确定word的开头和结尾,这对不使用空格作为分隔符的语言是一个限制,如中文、日文或韩文等语言。为了解决这一限制,从MySQL 5.7.6开始,MySQL提供了ngram全文解析器,InnoDBMyISAM存储引擎均支持ngram全文解析器。

ngram就是一段文字里面连续的n个字的序列。ngram全文解析器能够对文本进行分词,每个单词是连续的n个字的序列。例如,可以使用 ngram 全文解析器将 abcd标记为不同的值:

n=1: 'a', 'b', 'c', 'd'
n=2: 'ab', 'bc', 'cd'
n=3: 'abc', 'bcd'
n=4: 'abcd'

ngram 全文解析器是一个内置的服务器插件。与其他内置插件一样,它会在MySQL服务启动时自动加载。

ngram配置

MySQL 中使用全局变量ngram_token_size来配置ngramn的大小,它的取值范围是1到10,默认值是2。当标记大小为 2 时,ngram 解析器将字符串abc def解析为四个标记: abbcdeef

注意:如果需要搜索单字,就要把ngram_token_size设置为1。在默认值是2的情况下,搜索单字是得不到任何结果的。因为中文单词最少是两个汉字,推荐使用默认值2。

作为只读变量, ngram_token_size只能在MySQL启动命令参数中设置或在配置文件中设置:

全文搜索对于使用 ngram 解析器 的索引,以下配置项将会失效: innodb_ft_min_token_sizeinnodb_ft_max_token_sizeft_min_word_lenft_max_word_len

创建使用 ngram 解析器的全文索引

示例如下:

mysql> CREATE TABLE articles (
    ->       id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
    ->       title VARCHAR(200),
    ->       body TEXT,
    ->       FULLTEXT (title,body) WITH PARSER ngram
    ->     ) ENGINE=InnoDB CHARACTER SET utf8mb4;
Query OK, 0 rows affected (0.09 sec)

mysql> INSERT INTO articles (title,body) VALUES
    ('在哪儿都是锋霸!多特475万买莱万,20岁的他在波兰824119','莱万在今天凌晨的欧冠比赛攻入了自己个人的欧冠百球,这位波兰神锋在36岁的年纪仍是老当益壮。在登陆五大联赛之前,莱万效力波兰球队波兹南莱赫,20岁出头的他效力波兹南莱赫两个赛季,出战82场收获4119助。多特将他带到德甲时,是在2010年,当时大黄蜂花费了475万欧元。'),
    ('曼城本赛季英超+欧冠6次因失误导致丢球,整个上赛季只有4','曼城近期状态糟糕,在3-3被费耶诺德逼平之后,已经遭遇连续六场不胜,球队防线也是饱受诟病。

据天空体育统计,曼城本赛季在英超以及欧冠中由于失误导致6粒失球,已超过了整个上赛季的数据。');
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0

如果向现有表添加索引,可以使用alter tablecreate index

CREATE TABLE articles (
      id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
      title VARCHAR(200),
      body TEXT
     ) ENGINE=InnoDB CHARACTER SET utf8mb4;

ALTER TABLE articles ADD FULLTEXT INDEX ft_index (title,body) WITH PARSER ngram;

# 或:

CREATE FULLTEXT INDEX ft_index ON articles (title,body) WITH PARSER ngram;

ngram解析器空间处理

ngram 解析器在解析时消除了空格。例如:

ngram 解析器停用词处理

内置的 MySQL 全文解析器将单词与停用词列表中的条目进行比较。如果一个词等于停用词列表中的一个条目,则该词将从索引中排除。对于 ngram 解析器,停用词处理的执行方式不同。ngram 解析器不排除与停用词列表中的条目相等的标记,而是排除 包含停用词的标记。例如,ngram_token_size=2会将包含a,b的记录被解析为a,,b。如果将逗号,设置为停用词,则两者a,,b被排除在索引之外,因为它们包含逗号。

默认情况下,ngram 解析器使用默认停用词列表,其中包含英语停用词列表。对于适用于中文、日语或韩语的停用词列表,你必须创建自己的停用词列表。有关创建停用词列表的信息,请查阅官方文档

长度大于ngram_token_size 的停用词会被忽略。

ngram 解析器术语搜索

对于自然语言natural language模式搜索,搜索词被转换为ngram词的并集。比如,字符串abcngram_token_size=2时)被转换为ab bc,给定两个文档,一个包含ab,另一个包含 abc,搜索词ab bc匹配两个文档。

对于布尔Boolean模式搜索,搜索词被转换为 ngram 短语搜索。比如,字符串abcngram_token_size=2时)被转换为ab bc,给定两个文档,一个包含ab,另一个包含abc,搜索短语ab bc仅匹配包含bc的文档。

ngram 解析器通配符搜索

ngram解析器通配符搜索可能会返回意外结果:

ngram 解析器短语搜索

例如,搜索abc会被转换为ab bc,返回包含abcab bc的文档。

搜索abc def转换为 ab bc de ef,返回包含 abc defab bc de ef的文档。不返回 包含abcdef的文档。