全文本搜索
2019年8月14日大约 4 分钟约 1145 字
1. 背景与概念
使用LIKE
和正则表达式提供的搜索机制在性能和明确控制上存在限制,因此需要使用全文本搜索。
在全文本搜索中,MySQL 不需要分别查看每个行,不需要分别分析和处理每个词,其创建指定列中各词的一个索引,搜索可以针对这些词进行。这样,MySQL 可以快速有效地决定哪些词匹配(哪些行包含他们)或不匹配,它们匹配的频率等等。
为了进行全文本搜索,必须索引被搜索的列,而且要随着数据的改变不断地重新索引。
2. 相关语法
2.1 FULLTEXT 子句
- 可以在创建表时指定
FULLTEXT
- 也可以之后指定
FULLTEXT
- 但是不应该在导入数据时启用
FULLTEXT
索引,应该先导入所有数据,然后指定FULLTEXT
索引,这样有助于更快地导入数据
CREATE TABLE productnotes
(
note_id int NOT NULL AUTO_INCREMENT,
prod_id char(10) NOT NULL,
note_date datetime NOT NULL,
note_text text NULL,
PRIMARY KEY(note_id),
FULLTEXT(note_text)
) ENGINE=MyISAM;
2.2 Match()/Against()
- 两个函数搭配来进行全文本搜索,其中
Match()
指定搜索列,Against()
指定搜索表达式 - 传递给
Match()
的值必须与FULLTEXT()
定义中的相同,若有多个列,必须按次序列出它们 - 搜索不区分大小写。除非使用
BINARY
方式
SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('rabbit');
2.3 结果有排序
- 全文本搜索返回以文本匹配的良好程度排序的数据,具有较高等级的行先返回。
- 等级由 MySQL 根据行中词的数目、唯一词的数目、整个索引中词的总数以及包含该词的行的数目计算出来。
- 如果指定多个搜索项,则包含多数匹配词的行比包含较少词的那些行等级要高。
SELECT note_text
Match(note_text) Against('rabbit') AS rank
FROM productnotes;
3. 查询扩展
查询扩展用来设法放宽所返回的全文本搜索结果的范围。在使用查询扩展时,MySQL 对数据和索引进行两遍扫描来完成搜索:
- 进行一个基本的本文本搜索,找出与搜索条件匹配的所有行;
- MySQL 检查这些匹配行并选择所有有用的词;
- MySQL 再次进行全文本搜索,这次不仅使用原来的条件,还使用所有有用的词。
SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('anvils');
/* 输出
+-------------------------------------------------------+
|note_text|
+-------------------------------------------------------+
|Multiple customer returns, anvils failing to drop fast |
|enough or failing backward on purchaser. Recommend | |that customer considers using heavier anvils. |
+-------------------------------------------------------+
*/
WITH QUERY EXPANSION
后:
SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('anvils' WITH QUERY EXPANSION);
4. 布尔全文本搜索
布尔全文本搜索是一种非常缓慢的操作,在即使没有定义FULLTEXT
索引的情况下也可以使用,但其可提供如下更多的细节:
- 要匹配的词
- 要排斥的词(如果某行包含这个词,即使其包含其他指定的词也不返回该行)
- 排列提示(指定某些词比其他词更重要,更重要的词等级更高)
- 表达式分组
4.1 IN BOOLEAN MODE
SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('heavy -rope*' IN BOOLEAN MODE);
在布尔方式中,返回值没有排序:
4.2 全文本布尔操作符
5. 全文本搜索的一些说明
- 在索引全文本数据时,短词被忽略且从索引中排除。短词定义为那些具有 3 个或 3 个以下字符的词(如果需要,这个数目可更改)
- MySQL 带有一个内建的 非用词 (stopword) 列表,这些词的索引时总是被忽略。如果需要,可以覆盖这个列表。
- MySQL 规定了一条 50% 规则——如果一个词出现在 50% 以上的和中,则将它作为一个非用词忽略。50% 规则不用于 IN BOOLEAN MODE 中。
- 如果表中的行数少于 3 行,全文本搜索不返回结果。因为每个词或者不出现,或者至少出现在 50%的行中。
- 忽略词中的单引号。例如 don't 索引为 dont
- 不具有词分隔符的语言不能恰当地返回全文本搜索结果,如日语和汉语
- 只有 MyISAM 引擎支持全文本搜索