MySQL全文本搜索、查询扩展和布尔文本搜索

引言

在MySQL中,我们经常使用文本搜索功能,比较熟悉的搜索:
(1)使用LIKE关键词,利用通配符匹配文本,如select col1 from table1 where col1 like 'abc%';
(2)使用正则表达式搜索(REGEXP),如select col1 from table1 where col1 regexp '[123]abc';

这两种搜索方式能满足我们大部分的需求,但是,这两种搜索方式也存在几点重要的限制:

  1. 性能:通配符和正则表达式匹配通常要求MySQL尝试匹配表中的所有的行,因此,随着数据的增加,这些搜索非常耗时。
  2. 明确控制:这两种搜索方式很难明确控制匹配什么,不匹配什么,如指定一个词必须匹配,另一个词必须不匹配。
  3. 智能化的结果:通配符搜索和正则表达式匹配仅能返回满足匹配条件的行,但是每个结果的匹配程度等不能体现。

因此,要解决这些问题,我们就需要用到全文本搜索。

在使用全文本搜索时,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列可以在创建表的时候指定,也可以在已有表格上指定。

注意:

  1. 在使用全文本搜索时,必须使用MyISAM数据库引擎。其他数据库引擎如InnoDB不支持全文本搜索。
  2. 不要在导入数据的时候使用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行。

全文本搜索会根据行中词数目、唯一词的数目、整个索引中词的总数以及包含该词的行的数目等,自动计算各个结果
的等级值。

注意:

  1. 传递给 match() 的值必须与 fulltext() 定义中的相同,如果指定多个列,则必须列出他们,而且次序正确。
  2. 全文本搜索不区分大小写,除非使用BINARY

二、使用查询扩展

查询扩展用来设法放宽所返回的全文本搜索结果的范围。在使用查询扩展时,MySQL对数据和索引进行两遍扫描来完成搜索:

  1. 首先,进行一次基本的全文本搜索,找出与搜索条件匹配的所有行;
  2. 其次,MySQL检查这些匹配的行,并选择所有有用的词;
  3. 再其次,MySQL再次进行全文本搜索,这次不仅使用原来的条件,而且使用第二步中选择的所有有用的词。
select col from table1 where match(col) against('abc' with query expansion);
搜索结果除了包含abc的行,MySQL还会根据包含abc的行中其他词语,搜索和这些词语相匹配的行,这样就扩大了
搜索范围。

三、布尔文本搜索

布尔文本搜索时全文本搜索的另一种形式,它相较于全文本搜索,可以指定以下细节:

  1. 要匹配的词;
  2. 要排斥的词(如果某行包含这个词,则不返回该行,即使这行包含其他指定的词);
  3. 排列提示(指定词的重要程度);
  4. 表达式分组;
  5. 另外一些内容。

布尔文本搜索不同于其他全文本搜索的地方在于:布尔文本搜索即使没有指定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的等级

注意:
排列而不排序,在布尔方式中,不按等级值降序来排序返回的结果。

四、全文本搜索的注意事项

  1. 在索引全文本数据时,短语被忽略且从索引中排除。短语定义为具有3个或3个以下字符的词。可以修改。
  2. MySQL带有一个内建的非用词(stopWord)列表,这些词在索引全文本数据时被忽略。可以覆盖这个列表。
  3. 许多词的出现频率很高,搜索它们会返回太多的结果,意义不大,因此,MySQL规定了一个50%规则:如果一个词出现在50%以上的行中,则将它作为一个非用词忽略。(50%规则不适用于布尔文本搜索)
  4. 如果表中的行数少于3行,则全文本搜索不返回任何结果,因为每个词都不出现或者出现在50%以上的行中。
  5. 忽略词中的单引号,如don’t的索引为dont。
  6. 不具有词分隔符的语言(如:汉语和日语),不能恰当的返回全文本搜索结果。
  7. 仅在MyISAM数据库引擎中支持全文本搜索。
发布了20 篇原创文章 · 获赞 10 · 访问量 1440

猜你喜欢

转载自blog.csdn.net/Jerry_Chang31/article/details/104896694
今日推荐