数据库入门:MySQL必知必会(十八)全文本搜索
十八、全文本搜索
01. 理解全文本搜索
MySQL支持几种基本的数据库引擎,并非所有的引擎都支持本书所描述的全文本搜索:两个最常使用的引擎为MyISAM和InnoDB,前者支持全文本搜索,而后者不支持。
前面介绍了LIKE关键字,它利用通配操作符匹配文本(和部分文本);使用正则表达式,可以编写查找所需行的非常复杂的匹配模式。
虽然这些搜索机制非常有用,但存在几个重要的限制:
- 性能: 通配符和正则表达式匹配通常要求MySQL尝试匹配表中所有行(而且这些搜索极少使用表索引),由于被搜索行数不断增加,这些搜索可能非常耗时;
- 明确控制: 使用通配符和正则表达式匹配,很难(而且并不总是能)明确地控制匹配什么和不匹配什么;例如:指定一个词必须匹配,一个词必须不匹配,而一个词仅在第一个词确实匹配的情况下才可以匹配或者才可以不匹配;
- 智能化的结果: 虽然基于通配符和正则表达式的搜索提供了非常灵活的搜索,但它们都不能提供一种智能化的选择结果的方法;例如,一个特殊词的搜索将会返回包含该词的所有行,而不区分包含单个匹配的行和包含多个匹配的行(按照可能是更好的匹配来排列它们)。
所有这些限制以及更多的限制都可以用全文本搜索来解决,在使用全文本搜索时,不需要分别查看每个行,不需要分别分析和处理每个词,创建指定列中各词的一个索引,搜索可以针对这些词进行。
02. 使用全文本搜索
为了进行全文本搜索,必须索引被搜索的列,而且要随着数据的改变不断地重新索引:
-
启用全文本搜索支持:
一般在创建表时启用全文本搜索,CREATE TABLE语句接受 FULLTEXT 子句:
1.1 CREATE TABLE语句定义表productnotes并列出它所包含的列,这些列中有一个名为note_text的列,子句FULLTEXT(note_text) 对它索引进行全文本搜索;
1.2 可以在创建表时指定FULLTEXT,或者在稍后指定,不要在导入数据时使用FULLTEXT; -
进行全文本搜索:
在索引之后,使用两个函数Match()和Against()执行全文本搜索(Match()指定被搜索的列,Against()指定要使用的搜索表达式)。
2.1 Match(note_text) 指示MySQL针对 指定的列 进行搜索,Against(‘rabbit’) 指定词 rabbit 作为搜索文本;
2.2 传递给Match() 的值必须与FULLTEXT()定义中的相同,如果指定多个列,则必须列出它们(而且次序正确);
2.3 也可以简单地用LIKE子句完成:
2.4 上述两条SELECT语句都不包含ORDER BY子句,全文本搜索返回以文本匹配的良好程度排序的数据,LIKE以不特别有用的顺序返回数据; -
使用查询扩展:
查询扩展用来设法放宽所返回的全文本搜索结果的范围:
找出所有提到anvils的注释,如果只有一个注释包含词anvils,但你还想找出可能与你的搜索有关的所有其他行,即使它们不包含词anvils;
在使用查询扩展时,MySQL对数据和索引进行两遍扫描来完成搜索:
3.1 首先,进行一个基本的全文本搜索,找出与搜索条件匹配的所有行;
3.2 其次,MySQL检查这些匹配行并选择所有有用的词;
3.3 再其次,MySQL再次进行全文本搜索,这次不仅使用原来的条件,而且还使用所有有用的词;
3.4 进行一个简单的全文本搜索:
3.5 使用查询扩展:
3.6 表中的行越多,使用查询扩展返回的结果越好; -
布尔文本搜索:
MySQL支持全文本搜索的另外一种形式——布尔方式(boolean mode),以布尔方式,可以提供关于如下内容的细节:
4.1 要匹配的词;
4.2 要排斥的词(如果某行包含这个词,则不返回该行,即使它包含其他指定的词也是如此);
4.3 排列提示(指定某些词比其他词更重要,更重要的词等级更高);
4.4 表达式分组;
即使没有FULLTEXT索引也可以使用,但这是一种非常缓慢的操作;
4.5 使用了关键字IN BOOLEAN MODE,但实际上没有指定布尔操作符,其结果与没有指定布尔方式的结果相同;
匹配包含heavy但不包含任意以rope开始的词的行:
4.6 -rope*:明确地指示MySQL排除包含rope*(任何以rope开始的词,包括ropes)的行;
全文本布尔操作符:
举几个例子,说明某些操作符如何使用: -
全文本搜索的使用说明:
5.1 在索引全文本数据时,短词被忽略且从索引中排除,短词定义为那些具有3个或3个以下字符的词(如果需要,这个数目可以更改);
5.2 MySQL带有一个内建的非用词(stopword)列表,这些词在索引全文本数据时总是被忽略(可以覆盖这个列表);
5.3 许多词出现的频率很高,搜索它们没有用处,MySQL规定了一条50%规则:如果一个词出现在50%以上的行中,则将它作为一个非用词忽略,50%规则不用于IN BOOLEAN MODE;
5.4 如果表中的行数少于3行,则全文本搜索不返回结果;
5.5 忽略词中的单引号,例如:don’t索引为dont;
5.6 不具有词分隔符(包括日语和汉语)的语言不能恰当地返回全文本搜索结果。