引言
在MySQL中,我们经常使用文本搜索功能,比较熟悉的搜索:
(1)使用LIKE关键词,利用通配符匹配文本,如select col1 from table1 where col1 like 'abc%';
(2)使用正则表达式搜索(REGEXP),如select col1 from table1 where col1 regexp '[123]abc';
这两种搜索方式能满足我们大部分的需求,但是,这两种搜索方式也存在几点重要的限制:
- 性能:通配符和正则表达式匹配通常要求MySQL尝试匹配表中的所有的行,因此,随着数据的增加,这些搜索非常耗时。
- 明确控制:这两种搜索方式很难明确控制匹配什么,不匹配什么,如指定一个词必须匹配,另一个词必须不匹配。
- 智能化的结果:通配符搜索和正则表达式匹配仅能返回满足匹配条件的行,但是每个结果的匹配程度等不能体现。
因此,要解决这些问题,我们就需要用到全文本搜索。
在使用全文本搜索时,MySQL不需要分别查看每个行,不需要分别分析和处理每个词。MySQL创建指定列中各词的一个索引,搜索可以针对这些词进行。这样,MySQL可以快速有效的决定哪些词匹配,哪些词不匹配,以及他们匹配的频率,等等。
一、使用全文本搜索
使用全文本搜索时,必须要索引被搜索的列,而且要随着数据的改变不断重新索引,不过不用担心,我们对表列进行设计后,MySQL会自动进行索引和重新索引。
1.启用全文本搜索
在创建表的时候,通过指定FULLTEXT列来启用全文本搜索。如:
create table table1
(
id int not null auto_increment,
name char(20) not null,
dates datetime not null,
texts text null,
primary key(id),
FULLTEXT(texts)
)engine=MyISAM;
这样,MySQL会根据 **fulltext(texts)**对texts列进行自动索引,并自动维护该索引。当然,也可以指定多个列为索引列。
FULLTEXT列可以在创建表的时候指定,也可以在已有表格上指定。
注意:
- 在使用全文本搜索时,必须使用MyISAM数据库引擎。其他数据库引擎如InnoDB不支持全文本搜索。
- 不要在导入数据的时候使用FULLTEXT,这样会降低效率,消耗更多时间。
2.使用全文本搜索
使用全文本搜索时,使用**match()和against()**函数来进行。其中,**match()**指定被搜索的列,**against()**指定要使用的搜索表达式。
#搜索文本abc
select col from table1 where match(col) against('abc');
该行代码将返回含有abc的词的行,并且会根据匹配程度进行返回,匹配程度高的将优先返回,返回结果为按照匹配
程度排序好的结果。如:第4行行第2个词为abc,第3行第5个词为abc,将先返回第4行,再返回第3行。
全文本搜索会根据行中词数目、唯一词的数目、整个索引中词的总数以及包含该词的行的数目等,自动计算各个结果
的等级值。
注意:
- 传递给 match() 的值必须与 fulltext() 定义中的相同,如果指定多个列,则必须列出他们,而且次序正确。
- 全文本搜索不区分大小写,除非使用BINARY。
二、使用查询扩展
查询扩展用来设法放宽所返回的全文本搜索结果的范围。在使用查询扩展时,MySQL对数据和索引进行两遍扫描来完成搜索:
- 首先,进行一次基本的全文本搜索,找出与搜索条件匹配的所有行;
- 其次,MySQL检查这些匹配的行,并选择所有有用的词;
- 再其次,MySQL再次进行全文本搜索,这次不仅使用原来的条件,而且使用第二步中选择的所有有用的词。
select col from table1 where match(col) against('abc' with query expansion);
搜索结果除了包含abc的行,MySQL还会根据包含abc的行中其他词语,搜索和这些词语相匹配的行,这样就扩大了
搜索范围。
三、布尔文本搜索
布尔文本搜索时全文本搜索的另一种形式,它相较于全文本搜索,可以指定以下细节:
- 要匹配的词;
- 要排斥的词(如果某行包含这个词,则不返回该行,即使这行包含其他指定的词);
- 排列提示(指定词的重要程度);
- 表达式分组;
- 另外一些内容。
布尔文本搜索不同于其他全文本搜索的地方在于:布尔文本搜索即使没有指定fulltext列也可以进行,只是效率很低。
select col from table1 where match(col) against('abc -def' in boolean mode);
搜索包含abc但不包含def的行。
全文本布尔操作符
布尔操作符 | 说明 |
---|---|
+ | 包含,词必须存在 |
- | 排除,词必须不存在 |
> | 包含,并且增加等级值 |
< | 包含,并且减小等级值 |
() | 把词组成子表达式(允许这些子表达式作为一个组被包含、排除、排列等) |
~ | 取消一个词的排序值 |
* | 词尾的通配符 |
“ ” | 定义一个短语(与单个词的列表不一样,它匹配整个短语,以便包含或排除这个短语) |
例如:
select col from table1 where match(col) against('+abc +def' in boolean mode);
#匹配包含abc和def的行
select col from table1 where match(col) against('abc def' in boolean mode);
#匹配包含abc或def的行
select col from table1 where match(col) against('"abc def"' in boolean mode);
#匹配包含abc def这个词的行,而不是分开abc和def
select col from table1 where match(col) against('>abc <def' in boolean mode);
#匹配abc和def,但是增加abc的等级(重要性),减少def的等级(重要性)
select col from table1 where match(col) against('+abc +(<def)' in boolean mode);
#匹配abc和def,并且降低def的等级
注意:
排列而不排序,在布尔方式中,不按等级值降序来排序返回的结果。
四、全文本搜索的注意事项
- 在索引全文本数据时,短语被忽略且从索引中排除。短语定义为具有3个或3个以下字符的词。可以修改。
- MySQL带有一个内建的非用词(stopWord)列表,这些词在索引全文本数据时被忽略。可以覆盖这个列表。
- 许多词的出现频率很高,搜索它们会返回太多的结果,意义不大,因此,MySQL规定了一个50%规则:如果一个词出现在50%以上的行中,则将它作为一个非用词忽略。(50%规则不适用于布尔文本搜索)
- 如果表中的行数少于3行,则全文本搜索不返回任何结果,因为每个词都不出现或者出现在50%以上的行中。
- 忽略词中的单引号,如don’t的索引为dont。
- 不具有词分隔符的语言(如:汉语和日语),不能恰当的返回全文本搜索结果。
- 仅在MyISAM数据库引擎中支持全文本搜索。