一、FULLTEXT简介
  • MySQL具备全文搜索的能力,它可以让你在不使用模板匹配操作的情况下进行单词或短语的查找。
  • 全文搜索有3种类型:
    • 自然语言搜索(默认类型)。MySQL会把搜索字符串解析成一系列的单词 ,然后搜索出包含这些单词的那些行。
    • 布尔模式捜索。在捜索字符串里那些单词可以包含修饰字符,用以表明某些特定的要求,如某个给定的单词必须出现(或不出现)在匹配行里,或者某些行必须恰好包含某个短语。
    • 查扩展搜索。这种搜索分两阶段进行。第一阶段是自然语言搜索。第二阶段则先把原来的搜索字符串,与在第一阶段的捜索里高度匹配的那些行,连接在一起,然后再进行一次搜索。这种做法扩大了捜索范围,可以把那些与原有捜索字符串相关、但用这些字符串却匹配不到的那些行也找出来。
  • 要想对某个给定表进行全文搜索,则必须事先为它创建一个特殊类型的索引,这种索引具有以下几个方面的特点
  • 全文搜索基于FULLTEXT索引
    • 在MySQL 5.5里,这些索引只能针对MylSAM类型的表创建。MySQL 5.6引入了对InnoDB的全文捜索支持。
    • 在FULLTEXT索引里,只能包含CHAR、VARCHAR和TEXT这几种类型的列。
  • 全文搜索将会忽略掉那些常见词:
    • 这里的“常见”指的是“至少在一半的行里都出现过”。牢记这一点很重要,尤其是当你在建立测试表,以体验FULLTEXT功能的时候。
    • 在测试表里,你至少需要插入3个行。如果那个表只有一两个行,那么它里面的每个单词将至少有50%的出现几率,所以对它进行全文搜索将不会得到任何结果!
  • 有些内建的常用单词,如“the”、“after”和“other”等。它们都被称为“停用词”(stopword),在进行全文搜索时总是会被忽略掉
  • 太短的单词也会被忽略。默认情况下,“太短”指少于4个字符。不过,你可以重新配置服务器,把这个最小长度设置为其他值。更多相关信息请参考2.14.4节。
  • 全文搜索对“单词”的定义是,它们是由字母、数字、撇号和下划线构成的字符序列
    • 这意味着会把像“Mi-blooded”这样的字符串当成两个单词——"full"和“blooded”。一般情况下,全文搜索会匹配整个单词,而不会匹配部分单词
    • 通常情况下,只要在某个行里找到了搜索字符串里的某个单词,那么FULLTEXT引擎便会认为这个行与搜索字符串相匹配。
    • 如果你使用的是布尔式全文搜索,那么你可以加上一些额外的约束条件,如要求所有的单词都必须存在(或者以任何顺序,或者严格按照捜索字符串里的顺序进行短语搜索)。还可以用布尔搜索来匹配那些不包含特定单词的行,或者通过添加一个通配符来匹配所有以一个给定前缀开头的单词。
  • 可以为单个列或多个列创建FULLTEXT索引:
    • 如果它涉及多个列,基于该索引的搜索将在所有列上同进行。反过来也就是说,在进行全文搜索时,你给出的列列表必须和某个FULLTEXT索引所匹配的那些列精确匹配。
    • 例如,有时想捜索col1,有时想搜索col2,而有时想同时捜索col1和col2;那么,这时你需要创建3个索引,即两个列各占一个,而两个列的组合需要占一个。
  • FULLTEXT索引与其他索引的创建方法大同小异。你可以在开始创建表的时候,在CREATE TABLE语句里定义它;也可以先创建表,然后再用ALTER TABLE或CREATE INDEX来添加它。因为FULLTEXT索引要求必须使用MylSAM类型的表,所以如果你正在创建一个新的需要使用全文搜索的表,那么可以顺便利用一下MylSAM存储引擎的其中一个特性:如果采用先填充表,然后再添加索引的方式,而不是采用将数据加载到已经索引过的表中的方式,那么表的加载过程会变得更快一些。
  • 接下来的几个示例将会演示如何使用全文搜索,这些示例首先创建了几个FULLTEXT索引,然后使用MATCH运算符来査询它们。本文用到了两个文件,这些文件提供了一个用来创建表的脚本,以及一些需要加载到其中的样本数据,分别如下所示:
    • apothegm.txt的数据文件,其中内容是一些名人及他们的名言信息。
    • 如果按“名人”、“名言”和“名人加名言”来搜索,那么你需要创建3个FULLTEXT索引:两个列各算一个,这两列加起来算一个。根据这些内容,可以创建如下名为apothegm的表,并对它进行填充和索引。

MySQL FULLTEXT全文索引_FULLTEXT

# create, load, index theh apothegm table
DROP TABLE IF EXISTS apothegm;
#@ _SETUP_TABLE_
CREATE TABLE apothegm (attribution VARCHAR(40), phrase TEXT) ENGINE=MyISAM;
LOAD DATA LOCAL INFILE 'apothegm.txt' INTO TABLE apothegm;
ALTER TABLE apothegm
  ADD FULLTEXT (phrase),
  ADD FULLTEXT (attribution),
  ADD FULLTEXT (phrase, attribution);
#@ _SETUP_TABLE_
Aeschylus	Time as he grows old teaches many lessons
Alexander Graham Bell	Mr. Watson, come here. I want you!
Benjamin Franklin	It is hard for an empty bag to stand upright
Benjamin Franklin	Little strokes fell great oaks
Benjamin Franklin	Remember that time is money
Miguel de Cervantes	Bell, book, and candle
Proverbs 15:1	A soft answer turneth away wrath
Theodore Roosevelt	Speak softly and carry a big stick
William Shakespeare	But, soft! what light through yonder window breaks?
Robert Burton	I light my candle from their torches.
二、自然语言FULLTEXT所搜
  • 在创建好表之后,便可以用运算符MATCH列出一个或多个用于搜索的列,并用AGAINST()指定搜索字符串,对表进行自然语言类型的全文搜索。例如:
SELECT * FROM apothegm WHERE MATCH(attribution) AGAINST('roosevelt');
SELECT * FROM apothegm WHERE MATCH(phrase) AGAINST('time');
SELECT * FROM apothegm WHERE MATCH(attribution, phrase) AGAINST('bell');

MySQL FULLTEXT全文索引_搜索_02

  • 在最后这个示例里,要注意这条査询语句是如何在不同的列里将包含搜索单词的各个行査找出来的,其中也演示了利用FULLTEXT索引同时搜索多个列的功能。另外还要注意,在这条査询语句里以名字方式列出来的各个列的顺序是:attribution,phrase。这与在创建索引时列出来的顺序(即phrase,attribution)并不相同。由此说明这里的顺序并不重要。重要的是,这里必须要有一个FULLTEXT索引,而它正好是由査询命令里列出的那些列组成的。
  • 如果只想看看某个搜索可以匹配到多少个行,那么可以使用COUNT(*):
SELECT COUNT(*) FROM apothegm WHERE MATCH(phrase) AGAINST('time');

MySQL FULLTEXT全文索引_搜索_03

MATCH的相关度

  • 当你在WHERE子句里使用MATCH表达式时,对于自然语言类型的全文搜索,其输出行是按照相关程度递减顺序排列的。
  • 相关度是一个非负浮点数,其中零代表“毫不相关”。要想査看这些值,可以在输出列的列表里加上一个MATCH表达式:
SELECT phrase, MATCH(phrase) AGAINST('time') AS relevance FROM apothegm;

MySQL FULLTEXT全文索引_FULLTEXT_04

  • 自然语言捜索能够将包含所有搜索单词的那些行找出来,因此下面这条査询语句将把所有包含单词“hard”或“soft”的行找出来:
SELECT * FROM apothegm WHERE MATCH(phrase) AGAINST('hard soft');

MySQL FULLTEXT全文索引_字符串_05

  • 自然语言模式是默认的全文搜索模式。如果想要显式地指定这个模式,那么可以在搜索字符串的后面加上IN NATURAL LANGUAGE MODE。下面这条语句可以完成与前面那个示例完全一样的事情:
SELECT * FROM apothegm WHERE MATCH(phrase) AGAINST('hard soft' IN NATURAL LANGUAGE MODE);

MySQL FULLTEXT全文索引_全文索引_06

三、布尔模式的全文搜索
  • 通过使用布尔模式的全文搜索,可以获得对多单词(multiple-word)搜索的更多控制。要完成这种类型的捜索,需要在AGAINST()函数里搜索字符串的后面添加IN BOOLEAN MODE

布尔模式搜索的几个特点

  • “50%规则”不再起作用。即使找到的单词会出现在一半以上的行里,仍然会把它们搜索出来。
  • 査询结果不再按相关程度排序
  • 搜索可以要求短语里的所有单词都必须是按某种特定的顺序出现。如果想要匹配一个短语,那么需要把它用双引号引起来。只有在行包含的那些单词及其顺序与短语里列出的内容一致时,才会被认为是匹配上了:
SELECT * FROM apothegm WHERE MATCH(attribution, phrase) AGAINST('bell book and candle' IN BOOLEAN MODE);

MySQL FULLTEXT全文索引_FULLTEXT_07

  • 也可以对未被包括在FULLTEXT索引里的那些列,进行布尔模式的全文搜索,只是这样做会比对索引过的列进行捜索要慢一些
  • 对于布尔模式搜索,还可以为搜索字符串里的单词加上一些修饰符
    • 在单词的前面加上一个加号,则表示该单词必须出现在匹配行里。
    • 而加上一个减号,则表示该单词不能出现在匹配行里。
    • 例如,搜索字符串'bell'会匹配到所有包含“bell”的行。但在布尔模式下,捜索字符串'+bell -candle'则只会与那些包含了“bell”但不包含“candle”的行相匹配。
SELECT * FROM apothegm WHERE MATCH(attribution, phrase) AGAINST('bell');
SELECT * FROM apothegm WHERE MATCH(attribution, phrase) AGAINST('+bell -candle' IN BOOLEAN MODE);

MySQL FULLTEXT全文索引_字符串_08

  • 单词末尾的星号是一个通配符,只要行包含的单词是以搜索单词开头的,那么这些行就是匹配的。例如,'soft*',与“soft”、“softly”、“softness”等都匹配:
SELECT * FROM apothegm WHERE MATCH(phrase) AGAINST('soft*' IN BOOLEAN MODE);

MySQL FULLTEXT全文索引_全文搜索_09

  • 不过,不能用这个通配符功能来匹配那些比最小索引单词长度还要短的单词。另外,其他所有的布尔模式修饰符请参阅相关文档。
  • 与自然语言全文搜索相似,布尔模式的全文搜索也会把所有停用词忽略掉,即使它们被标记为“必需的”也是一样。例如,捜索'+Alexander +the +great'将把那些包含“Alexander”和“great”的行找出来,而“the”则会因其是一个停用词而被忽略
四、查询扩展全文搜索
  • 支持查询扩展的全文捜索会分两个阶段完成搜索
    • 第一阶段搜索与普通的自然语言捜索一样。在这次捜索里,那些相关程度最高的行会被用用于第二阶段的捜索。这些行里的单词会与原来那些搜索单词一起使用,完成第二阶段的搜索。
    • 因为整个搜索单词的集合变得更大了,所以在最终的结果里会包含一些在第一阶段未被找到,但又与它们有着密切联系的行。
  • 要想完成这种搜索,需要在搜索字符串的后面加上WITH QUERY EXPANSION。下面这个示例可用于说明整个过程:
    • 第一条查询命令展示的是一次自然语言捜索
    • 第二条査询命令展示的是一次査询扩展搜索。这次查询多找到了一行记录,而它并没有包含原始搜索字符串里的那些单词。之所以能找到该行,是因为它包含单词“candle”,而这个单词存在于那个自然语言搜索所找到的行里。
SELECT * FROM apothegm WHERE MATCH(attribution, phrase) AGAINST('bell book');
SELECT * FROM apothegm WHERE MATCH(attribution, phrase) AGAINST('bell book' WITH QUERY EXPANSION);

MySQL FULLTEXT全文索引_FULLTEXT_10

五、配置全文搜索引擎
  • 全文搜索有几个参数是可配置的,并且可以通过设置系统变量的办法进行修改。
  • 变量ft_min_word_len和ft_max_word_len用于确定FULLTEXT索引里的那些单词所具有的最小长度和最大长度。在创建FULLTEXT索引时,会忽略掉其长度超出这两个参数所确定的范围的那些单词。默认的最小值和最大值分别是4和84。
  • 假设想要把最小单词长度从4改成3,那么可按以下步骤进行操作。
  • (1)把ft_ndn_word_len变量设置为3,重启服务器。如果想让这个设置在每次服务器重启时都能生效,那么最好的办法是把这个设置放到某个选项文件里,如/etc/nv.cnf文件:
[mysqld]
ft_min_word_len=3
  • (2)对于那些已经建立了FULLTEXT索引的表,必须重建这些索引。你可以先删除这些引,然后再重建它们,但更为简易有效的办法是执行一次快速修复操作:
REPAIR TABLE tbl_name QUICK;
  • (3)所有在更改参数后新创建的FULLTEXT索引,将自动使用这个新值。

说明

  • 如果想使用myisamchk程序为某个包含有FULLTEXT索引的表重建索引,那么可以参考附录F,其中在对myisamchk进行描述时包含了一些与FULLTEXT索引有关的注意事项。