为什么要使用全文本搜索?
其实有类似于全文本搜索的功能:
1、LIKE关键字:利用通配符操作匹配文本,使用LIKE,能够查找包含特殊值或部分值的行(不管这些值在什么位置)。
2、正则表达式:基于文本搜索的正则表达式可以编写查找所需行的更复杂的匹配模式。
尽管以上两种搜索匹配机制很有用,但是存在这么几个重要的限制:
a、性能–通配符和正则表达式匹配通常要求MYSQL尝试匹配表所有行(这些搜索极少使用变索引)。因此随着表数据的增加,这些搜索可能非常耗时;
b、明确控制–使用通配符和正则表达式很难明确地控制匹配什么和不匹配什么。例如指定一个词必须匹配,另一个词必须不匹配。
c、智能化的结果–通配符和正则表达式的搜索功能尽管强大,但是他们并不能提供一种智能化的选择结果的方法。如:一个特殊值的搜索会返回所有匹配的行,而不区分单个匹配的行与多个匹配的行(按照可能是更好匹配来排列搜索结果);一个特殊值的搜索将不会找出不包含该词组但包含其他相关词的行。
所有的这些限制吗,用全文本搜索都能得到很好的解决,而且在使用全文本搜索功能时,MYSQL不需要分别查看每个行,不需要分别分析和处理每个词、MYSQL创建指定列中各词的一个索引,搜索可以针对这些词进行,因此效率更高。
我们在使用MySQL时,一般会用到两种引擎--MyISAM和InnoDB,MyISAM支持全文本搜索,但不支持事务处理;而InnoDB支持事务处理,但不支持全文本搜索,因此当你要在某个表(一般是包含长文本字段的表)中使用全文本搜索功能时,选择引擎的时候就要选MyISAM了。
一、全文本搜索使用
有时,我们需要使用全文本搜索,例如:要搜索文本中存在指定的某个词,且以这个词出现的顺序排序。
先创建支持全文本搜索的表:
CREATE TABLE product_notes
(
note_id int NOT NULL AUTO_INCREMENT,
note_date datetime NOT NULL,
note_text text NULL,
PRIMARY KEY(note_id),
FULLTEXT(note_text)
) ENGINE=MyISAM;
注意:要使用全文本搜索,引擎一定要是MyISAM(ENGINE=MyISAM)。
在note_text字段定义了全文本搜索功能后,MySQL会自动为这列添加索引,并维护该索引。在增加,更新或删除行时,索引随之自动更新。如果需要,也可以给多个列添加索引。
MYSQL中使用Match()和Against()函数进行全文本搜索。
假设product_notes表中已经有了数据,现在我们来使用全文本查询:
SELECT note_text FROM product_notes WHERE Match(note_text) Against(‘rabbit’);
这条语句检索出note_text字段包含rabbit的行。类似于:
SELECT note_text FROM product_notes WHERE note_text like ‘%rabbit%’;
两者的区别在于使用like查询仅仅只返回包含‘rabbit’的行,而使用全文本会按’rabbit’在文本中出现的顺序排序,这是like所做不到的。例如(假设note_text字段存在两行包含rabbit的行):
1:A fat rabbit
2:A rabbit
用全文本搜索出来就的排序就会这样
2:A rabbit
1:A fat rabbit
因为2中的rabbit前面只有一个词,而1中的有两个,所以2的优先级高,自然排在前面。
但是LIKE关键字返回的结果只是按默认的排序规则。
如何查看优先级?一般是按照搜索值在行中的前后顺序排列的,越靠前等级越高。当然我们可以用代码查看:
SELECT note_text,Match(note_text) Against(‘rabbit’) AS rank FROM product_notes;
返回:
note_text rank
1:A fat rabbit 1.5935389274914
2:A rabbit 1.6403435232543
3:A good day 0
4:To do it 0
由此我们可以看出,不包含关键字rabbit的行的等级为0,包含rabbit关键字的,rabbit越靠前,等级越高。
这个例子也说明全文本搜索如何排除行(排除那些等级为0的行),如何排序结果(按等级降序排列)。
二、使用查询扩展
SELECT note_text FROM product_notes WHERE Match(note_text) Against('rabbit' WITH QUERY EXPANSION);
返回:
2:A rabbit
1:A fat rabbit
3:A good day
查询扩展用来设法放宽所返回的全文本搜索结果的范围。
因为3存在一个A(依赖于1和2中的A,即会把相关的行返回回来,类似于有一行里面包含thinkphp和tp关键字,当你用查询扩展查询thinkphp时,仅仅包含tp的行也会返回回来),所以也被查询出来了。
查询扩展极大的增加了返回的行数,但这样做实际上增加了你可能并不想要的数据,另外,表中的行数越多,使用查询扩展返回的结果就会越好!因此,请酌情使用。
三、布尔文本搜索
布尔操作符 描述
+ 包含指定值
- 排除指定值
> 包含指定值,并且增加优先级值
< 包含指定值,并且减少优先级值
() 把词组成表达式
~ 取消一个词的排序值
* 词尾的通配符
“” 定义一个短语
下面给出一些例子:
SELECT note_text FROM product_notes WHERE Match(note_text) Against('+rabbit +fat' IN BOOLEAN MODE);
返回:
2:A fat rabbit
返回的行必须同时包含关键字 rabbit 和 fat
SELECT note_text FROM product_notes WHERE Match(note_text) Against('rabbit -fat' IN BOOLEAN MODE);
返回:
2:A rabbit
返回包含 rabbit 关键字 但不包含 fat 的行(a fat rabbit 不会被返回)
SELECT note_text FROM product_notes WHERE Match(note_text) Against('rabbit good' IN BOOLEAN MODE);
返回:
2:A rabbit
1:A fat rabbit
3:A good day
没有指定操作符,搜索包含rabbit或good的行(其中的一个或两个)。
SELECT note_text FROM product_notes WHERE Match(note_text) Against('"fat rabbit"' IN BOOLEAN MODE);
返回:
2:A fat rabbit
文本包含”fat rabbit”的行(现在关键字是“fat rabbit”)。
SELECT note_text FROM product_notes WHERE Match(note_text) Against('+fat +(>rabbit)' IN BOOLEAN MODE);
返回:
2:A fat rabbit
文本包含fat和rabbit的行,且增加后者的优先级值。
四、全文本搜索使用说明
1、指定值出现在行中的频率少于50% (频率太高,返回结果太多,没用)
2、忽略MySQL的内建非用词(stopword)
3、忽略单引号,如:don’t 搜索为dont
4、不具有词分隔符的语言(如:日语和汉语)不能恰当地返回全文本搜索结果
5、引擎必须是MyISAM类型
本文章参考自《mysql必知必会》