布尔全文搜索
在 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 解析器或 MeCab 解析插件构建的全文索引。参数 innodb_ft_min_token_size 和 innodb_ft_max_token_size 控制 InnoDB 搜索索引。参数 ft_min_word_len 和 ft_max_word_len 控制 MyISAM 搜索索引。最小字长、最大字长不适用于通过 ngram 解析器构建的 FULLTEXT 索引。参数 ngram_token_size 设定 Ngram 令牌数。
- 停用词表对于两种数据库引擎都适用,可通过参数 innodb_ft_enable_stopword、innodb_ft_server_stopword_table、innodb_ft_user_stopword_table 控制 InnoDB 搜索索引,通过参数 ft_stopword_file LAI 控制 MyISAM 搜索索引。
- InnoDB 全文搜索不支持为单个搜索词附加多个运算符,如:“++apple”,这种写法会报错。但 MyISAM 能处理这种情况,除紧邻该搜索词的运算符外,其余运算符将全部忽略。
- InnoDB 全文搜索仅支持前导 +/- 号。例如,InnoDB 支持“+apple”但不支持“apple+”,使用尾随加减号会报错。
- InnoDB 全文搜索不支持带通配符的前导加号 (’+*’),不支持组合加减号 (‘±’) ,也不支持前导组合加减号 (‘±apple’)。
- InnoDB 全文搜索不支持在布尔搜索中使用 @ ,它是一个保留符,用作 @distance proximity。
- 对于 MyISAM 搜索索引,50% 阈值不再适用。
布尔型全文搜索支持下列运算符:
- +
前导或尾随加号表示单词必须出现在返回行中。InnoDB 仅支持前导加号。 - -
前导或尾随减号表示单词不能出现在返回行中。InnoDB 仅支持前导减号。
注:- 表示在同其它搜索词匹配的结果集上剔除包含该关键词的行。因此,搜索“ -XXX”将返回空。 - (空操作符)
默认情况下(既不指定 + 也不指定 -),单词可以出现在结果中,也可以不出现,但包含该单词的行相关度评分更高。这与不带 IN BOOLEAN MODE 修饰符的 MATCH() AGAINST() 表达式功能相同。 - @distance
仅用于 InnoDB。计算两个以上搜索词是否两两间隔指定的字符数。在紧邻 @distance 运算符前面的双引号字符串内指定搜索词,例如,MATCH(col1) AGAINST(’“word1 word2 word3” @8’ IN BOOLEAN MODE)。 - > <
调整某个单词对行相关性大小的贡献度。> 增加贡献度,< 减少贡献度。请参考列表后面的栗子。 - ( )
将单词分组成子表达式。带括号的组可以嵌套。 - ~
前导波浪号,代表否定运算符,表示单词对所在行相关度的贡献值为负,可用来标注“噪声”词,十分方便。某一行若包含噪声词会降低其相关度评分,但不会像 - 运算符那样完全剔除包含该单词的行。 - *
用作截词符(或通配符),若单词以 * 前面的字串开始,则匹配。
一个词如果带有截词符,那么即使长度很短或者本身是一个停止词,也不会在布尔查询中剔除。判断一个词是否太短,取决于参数 innodb_ft_min_token_size (InnoDB) 或 ft_min_word_len (MyISAM) 所设置的大小。对于 ngram 解析器的 FULLTEXT 索引,以上选项不适用。
带通配符的字串作为一个前缀,必须出现在一个或多个单词的起始位置。如果将最小字长设为 4,那么搜索“+word +the*”可能会比搜索“+word +the”返回的行数少,原因是“the”过短,会在后一搜索中忽略。 - "
由一对双引号 (") 括起来的短语仅支持逐字匹配包含该短语的行。全文引擎将短语拆分为单词,并基于 FULLTEXT 索引完成搜索。非单词字符无需进行精确匹配,短语搜索只要求匹配项包含与短语完全相同、顺序一致的单词。例如,“test phrase”能匹配“test, phrase”。
如果该短语不包含索引中的单词,则结果为空。单词不在索引中有很多原因:文本中无该单词、本身是停用词、单词长度小于索引词的最小长度等。
下面列举了一些包含布尔全文运算符的搜索字串:
- ‘apple banana’
查找包含单词“apple”或“banana”或同时包含两者的行。 - ‘+apple +juice’
查找同时包含单词“apple”和“juice”的行。 - ‘+apple macintosh’
查找包含单词“apple”的行,如果该行也包含“Macintosh”,则排名更靠前。 - ‘+apple -macintosh’
查找包含单词“apple”但不包含“macintosh”的行。 - ‘+apple ~macintosh’
查找包含单词“apple”的行,但如果该行还包含单词“Macintosh”,则其评级低于不包含单词“Macintosh”的行。这实现了比“+apple -macintosh”稍“软”的弹性搜索,不是说出现“macintosh”就不返回该行,只是评级变低。 - ‘+apple +(>turnover <strudel)’
查找同时包含单词“apple”和“turnover”的行,或同时包含“apple”和“strudel”的行(按任意顺序),但匹配“apple torrence”的结果会排在“apple strudel”的结果前面。 - ‘apple*’
查找包含“apple”、“apples”、“applesauce”、“applet”等单词的行。 - ‘“some words”’
查找包含短语“some words”的行,且必须精确匹配(例如,包含“some words of willigence”的行能够匹配,而包含“some noise words”的行不能匹配)。
注:双引号 ” 应视为短语的界定符,而不应视为把搜索字符串本身括起来的引号。
相关性排序
InnoDB 全文搜索仿效了 Sphinx 全文搜索引擎,其搜索算法基于 BM25 和 TF-IDF,因此在相关度排序算法上可能与 MyISAM 有所不同。
给定一个查询,InnoDB 采用一种变体 TF-IDF 对检索文档进行相关度评级。TF-IDF 算法基于这样一种假设:一个单词在某个文档中出现的频率越高而在同一语料库其它文档中出现的频率越低,则该文档的重要性(或评级)就越高,排名也就越靠前。