文档首页
MySQL 9.0 参考手册
相关文档 下载本手册
PDF (US Ltr) - 40.0Mb
PDF (A4) - 40.1Mb
手册页 (TGZ) - 258.2Kb
手册页 (Zip) - 365.3Kb
信息 (Gzip) - 4.0Mb
信息 (Zip) - 4.0Mb


MySQL 9.0 参考手册  /  ...  /  布尔全文搜索

14.9.2 布尔全文搜索

MySQL 可以使用 IN BOOLEAN MODE 修饰符执行布尔全文搜索。使用此修饰符,某些字符在搜索字符串中单词的开头或结尾具有特殊含义。在以下查询中,+- 运算符分别表示匹配时单词必须存在或不存在。因此,该查询检索包含单词“MySQL” 但不包含单词“YourSQL” 的所有行。

mysql> SELECT * FROM articles WHERE MATCH (title,body)
    -> AGAINST ('+MySQL -YourSQL' IN BOOLEAN MODE);
+----+-----------------------+-------------------------------------+
| id | title                 | body                                |
+----+-----------------------+-------------------------------------+
|  1 | MySQL Tutorial        | DBMS stands for DataBase ...        |
|  2 | How To Use MySQL Well | After you went through a ...        |
|  3 | Optimizing MySQL      | In this tutorial, we show ...       |
|  4 | 1001 MySQL Tricks     | 1. Never run mysqld as root. 2. ... |
|  6 | MySQL Security        | When configured properly, MySQL ... |
+----+-----------------------+-------------------------------------+
注意

在实现此功能时,MySQL 使用有时称为 隐式布尔逻辑 的逻辑,其中

  • + 代表 AND

  • - 代表 NOT

  • [无运算符] 隐含 OR

布尔全文搜索具有以下特点:

  • 它们不会按相关性降序自动对行进行排序。

  • InnoDB 表需要在 MATCH() 表达式的所有列上都有一个 FULLTEXT 索引才能执行布尔查询。针对 MyISAM 搜索索引的布尔查询即使没有 FULLTEXT 索引也可以工作,但是以这种方式执行的搜索速度会非常慢。

  • 最小和最大单词长度全文参数适用于使用内置 FULLTEXT 解析器和 MeCab 解析器插件创建的 FULLTEXT 索引。对于 InnoDB 搜索索引,使用 innodb_ft_min_token_sizeinnodb_ft_max_token_size。对于 MyISAM 搜索索引,使用 ft_min_word_lenft_max_word_len

    最小和最大单词长度全文参数不适用于使用 ngram 解析器创建的 FULLTEXT 索引。ngram 标记大小由 ngram_token_size 选项定义。

  • 停用词列表适用,由 innodb_ft_enable_stopwordinnodb_ft_server_stopword_tableinnodb_ft_user_stopword_table 控制 InnoDB 搜索索引,由 ft_stopword_file 控制 MyISAM 搜索索引。

  • InnoDB 全文搜索不支持在单个搜索词上使用多个运算符,例如:'++apple'。在单个搜索词上使用多个运算符会向标准输出返回语法错误。MyISAM 全文搜索可以成功处理相同的搜索,忽略除紧邻搜索词的运算符之外的所有运算符。

  • InnoDB 全文搜索仅支持前导加号或减号。例如,InnoDB 支持 '+apple',但不支持 'apple+'。指定尾随加号或减号会导致 InnoDB 报告语法错误。

  • InnoDB 全文搜索不支持将前导加号与通配符 ('+*')、加号和减号组合 ('+-') 或前导加号和减号组合 ('+-apple') 一起使用。这些无效查询会返回语法错误。

  • InnoDB 全文搜索不支持在布尔全文搜索中使用 @ 符号。@ 符号保留供 @distance 邻近搜索运算符使用。

  • 它们不使用适用于 MyISAM 搜索索引的 50% 阈值。

布尔全文搜索功能支持以下运算符:

  • +

    前导或尾随加号表示此单词 必须 出现在返回的每一行中。InnoDB 仅支持前导加号。

  • -

    前导或尾随减号表示此单词 不得 出现在返回的任何行中。InnoDB 仅支持前导减号。

    注意:- 运算符仅用于排除其他搜索词匹配的行。因此,仅包含以 - 开头的词项的布尔模式搜索将返回空结果。它不会返回“除包含任何排除词项的行之外的所有行。”。

  • (无运算符)

    默认情况下(当未指定 +- 时),该单词是可选的,但包含该单词的行排名更高。这模拟了没有 IN BOOLEAN MODE 修饰符的 MATCH() AGAINST() 的行为。

  • @distance

    此运算符仅适用于 InnoDB 表。它测试两个或多个单词是否都从彼此指定的距离(以单词为单位)内开始。在 @distance 运算符之前的双引号字符串中指定搜索词,例如,MATCH(col1) AGAINST('"word1 word2 word3" @8' IN BOOLEAN MODE)

  • > <

    这两个运算符用于更改单词对分配给行的相关性值的贡献。> 运算符增加贡献,< 运算符减少贡献。请参阅此列表后的示例。

  • ( )

    括号将单词分组为子表达式。带括号的组可以嵌套。

  • ~

    前导波浪号充当否定运算符,导致该词对行相关性的贡献为负。这对于标记“噪声”词很有用。包含此类词的行评级低于其他行,但不会像使用 - 运算符那样被完全排除。

  • *

    星号充当截断(或通配符)运算符。与其他运算符不同,它被*附加*到要影响的词。如果词以 * 运算符之前的词开头,则匹配。

    如果使用截断运算符指定了一个词,则即使该词太短或为停用词,也不会从布尔查询中删除该词。一个词是否太短取决于 InnoDB 表的 innodb_ft_min_token_size 设置,或 MyISAM 表的 ft_min_word_len 设置。这些选项不适用于使用 ngram 解析器的 FULLTEXT 索引。

    带通配符的词被视为必须存在于一个或多个词开头的前缀。如果最小词长为 4,则搜索 '+word +the*' 返回的行数可能少于搜索 '+word +the' 返回的行数,因为第二个查询会忽略太短的搜索词 the

  • "

    用双引号 (") 字符括起来的短语仅匹配*按原样键入*包含该短语的行。全文引擎会将该短语拆分为单词,并在 FULLTEXT 索引中搜索这些单词。非单词字符不需要完全匹配:短语搜索仅要求匹配项包含与短语完全相同的单词,并且顺序相同。例如,"test phrase" 匹配 "test, phrase"

    如果短语中没有索引中存在的单词,则结果为空。这些词可能由于以下因素的组合而不在索引中:如果它们在文本中不存在、是停用词或短于索引词的最小长度。

以下示例演示了一些使用布尔全文运算符的搜索字符串

  • 'apple banana'

    查找包含两个单词中至少一个的 That 行。

  • '+apple +juice'

    查找包含这两个词的行。

  • '+apple macintosh'

    查找包含单词“apple”的行,但如果行也包含“macintosh”,则排名更高。

  • '+apple -macintosh'

    查找包含单词“apple”但不包含“macintosh”的行。

  • '+apple ~macintosh'

    查找包含单词“apple”的行,但如果该行也包含单词“macintosh”,则其评级低于不包含该词的行。这比搜索 '+apple -macintosh'“更软”,因为如果存在“macintosh”,则根本不会返回该行。

  • '+apple +(>turnover <strudel)'

    查找包含单词“apple”和“turnover”或“apple”和“strudel”(以任何顺序)的行,但“apple turnover”的排名高于“apple strudel”。

  • 'apple*'

    查找包含“apple”、“apples”、“applesauce”或“applet”等词的行。

  • '"some words"'

    查找包含确切短语“some words”的行(例如,包含“some words of wisdom”但不包含“some noise words”的行)。请注意,将短语括起来的 " 字符是界定短语的运算符字符。它们不是将搜索字符串本身括起来的引号。

InnoDB 布尔模式搜索的相关性排名

InnoDB 全文搜索以 Sphinx 全文搜索引擎为模型,使用的算法基于 BM25TF-IDF 排名算法。因此,InnoDB 布尔全文搜索的相关性排名可能与 MyISAM 的相关性排名不同。

InnoDB 使用“词频-逆文档频率”(TF-IDF)加权系统的变体来对给定全文搜索查询的文档相关性进行排名。TF-IDF 加权基于单词在文档中出现的频率,并通过单词在集合中所有文档中出现的频率进行抵消。换句话说,单词在文档中出现的频率越高,单词在文档集合中出现的频率越低,文档的排名就越高。

如何计算相关性排名

词频 (TF) 值是单词在文档中出现的次数。单词的逆文档频率 (IDF) 值使用以下公式计算,其中 total_records 是集合中的记录数,matching_records 是搜索词出现的记录数。

${IDF} = log10( ${total_records} / ${matching_records} )

当文档多次包含某个单词时,IDF 值将乘以 TF 值

${TF} * ${IDF}

使用 TFIDF 值,使用以下公式计算文档的相关性排名

${rank} = ${TF} * ${IDF} * ${IDF}

以下示例演示了该公式。

单个单词搜索的相关性排名

此示例演示了单个单词搜索的相关性排名计算。

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

mysql> INSERT INTO articles (title,body) VALUES
    ->   ('MySQL Tutorial','This database tutorial ...'),
    ->   ("How To Use MySQL",'After you went through a ...'),
    ->   ('Optimizing Your Database','In this database tutorial ...'),
    ->   ('MySQL vs. YourSQL','When comparing databases ...'),
    ->   ('MySQL Security','When configured properly, MySQL ...'),
    ->   ('Database, Database, Database','database database database'),
    ->   ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),
    ->   ('MySQL Full-Text Indexes', 'MySQL fulltext indexes use a ..');
Query OK, 8 rows affected (0.06 sec)
Records: 8  Duplicates: 0  Warnings: 0

mysql> SELECT id, title, body, 
    ->   MATCH (title,body) AGAINST ('database' IN BOOLEAN MODE) AS score
    ->   FROM articles ORDER BY score DESC;
+----+------------------------------+-------------------------------------+---------------------+
| id | title                        | body                                | score               |
+----+------------------------------+-------------------------------------+---------------------+
|  6 | Database, Database, Database | database database database          |  1.0886961221694946 |
|  3 | Optimizing Your Database     | In this database tutorial ...       | 0.36289870738983154 |
|  1 | MySQL Tutorial               | This database tutorial ...          | 0.18144935369491577 |
|  2 | How To Use MySQL             | After you went through a ...        |                   0 |
|  4 | MySQL vs. YourSQL            | When comparing databases ...        |                   0 |
|  5 | MySQL Security               | When configured properly, MySQL ... |                   0 |
|  7 | 1001 MySQL Tricks            | 1. Never run mysqld as root. 2. ... |                   0 |
|  8 | MySQL Full-Text Indexes      | MySQL fulltext indexes use a ..     |                   0 |
+----+------------------------------+-------------------------------------+---------------------+
8 rows in set (0.00 sec)

总共有 8 条记录,其中 3 条与“database”搜索词匹配。第一条记录(id 6)包含搜索词 6 次,相关性排名为 1.0886961221694946。此排名值是使用 TF 值 6(“database”搜索词在记录 id 6 中出现 6 次)和 IDF 值 0.42596873216370745 计算得出的,计算公式如下(其中 8 是记录总数,3 是搜索词出现的记录数)

${IDF} = LOG10( 8 / 3 ) = 0.42596873216370745

然后将 TFIDF 值输入排名公式

${rank} = ${TF} * ${IDF} * ${IDF}

在 MySQL 命令行客户端中执行计算将返回排名值 1.088696164686938。

mysql> SELECT 6*LOG10(8/3)*LOG10(8/3);
+-------------------------+
| 6*LOG10(8/3)*LOG10(8/3) |
+-------------------------+
|       1.088696164686938 |
+-------------------------+
1 row in set (0.00 sec)
注意

您可能会注意到 SELECT ... MATCH ... AGAINST 语句和 MySQL 命令行客户端返回的排名值略有差异(1.08869612216949461.088696164686938)。差异是由于 InnoDB 内部执行整数和浮点数/双精度数之间的转换方式(以及相关的精度和舍入决策),以及在其他地方(例如在 MySQL 命令行客户端或其他类型的计算器中)执行转换的方式不同造成的。

多个单词搜索的相关性排名

此示例演示了基于上一个示例中使用的 articles 表和数据的多个单词全文搜索的相关性排名计算。

如果搜索多个单词,则相关性排名值是每个单词的相关性排名值的总和,如以下公式所示

${rank} = ${TF} * ${IDF} * ${IDF} + ${TF} * ${IDF} * ${IDF}

搜索两个词('mysql tutorial')将返回以下结果

mysql> SELECT id, title, body, MATCH (title,body)  
    ->   AGAINST ('mysql tutorial' IN BOOLEAN MODE) AS score
    ->   FROM articles ORDER BY score DESC;
+----+------------------------------+-------------------------------------+----------------------+
| id | title                        | body                                | score                |
+----+------------------------------+-------------------------------------+----------------------+
|  1 | MySQL Tutorial               | This database tutorial ...          |   0.7405621409416199 |
|  3 | Optimizing Your Database     | In this database tutorial ...       |   0.3624762296676636 |
|  5 | MySQL Security               | When configured properly, MySQL ... | 0.031219376251101494 |
|  8 | MySQL Full-Text Indexes      | MySQL fulltext indexes use a ..     | 0.031219376251101494 |
|  2 | How To Use MySQL             | After you went through a ...        | 0.015609688125550747 |
|  4 | MySQL vs. YourSQL            | When comparing databases ...        | 0.015609688125550747 |
|  7 | 1001 MySQL Tricks            | 1. Never run mysqld as root. 2. ... | 0.015609688125550747 |
|  6 | Database, Database, Database | database database database          |                    0 |
+----+------------------------------+-------------------------------------+----------------------+
8 rows in set (0.00 sec)

在第一条记录(id 8)中,“mysql”出现一次,“tutorial”出现两次。“mysql”有六条匹配记录,“tutorial”有两条匹配记录。将这些值插入多个单词搜索的排名公式后,MySQL 命令行客户端将返回预期的排名值

mysql> SELECT (1*log10(8/6)*log10(8/6)) + (2*log10(8/2)*log10(8/2));
+-------------------------------------------------------+
| (1*log10(8/6)*log10(8/6)) + (2*log10(8/2)*log10(8/2)) |
+-------------------------------------------------------+
|                                    0.7405621541938003 |
+-------------------------------------------------------+
1 row in set (0.00 sec)
注意

SELECT ... MATCH ... AGAINST 语句和 MySQL 命令行客户端返回的排名值略有差异,这在上一个示例中已作解释。