需求产生
InnoDB 在模糊查询数据时使用 “%xx” 会导致索引失效,但有时需求就是如此,类似这样的需求还有很多,例如,搜索引擎需要根基用户数据的关键字进行全文查找,电子商务网站需要根据用户的查询条件,在可能需要在商品的详细介绍中进行查找,这些都不是B+树索引能很好完成的工作。
通过数值比较,范围过滤等就可以完成绝大多数我们需要的查询了。但是,如果希望通过关键字的匹配来进行查询过滤,那么就需要基于相似度的查询,而不是原来的精确数值比较,全文索引就是为这种场景设计的。
全文索引(Full-Text Search)是将存储于数据库中的整本书或整篇文章中的任意信息查找出来的技术。它可以根据需要获得全文中有关章、节、段、句、词等信息,也可以进行各种统计和分析。
在早期的 MySQL 中,InnoDB 并不支持全文检索技术,从 MySQL 5.6 开始,InnoDB 开始支持全文检索。
使用
创建全文索引
1、创建表时创建全文索引语法如下:
1 | CREATE TABLE table_name ( id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, author VARCHAR(200), |
2、在已创建的表上创建全文索引语法如下:
1 | CREATE FULLTEXT INDEX full_index_name ON table_name(col_name); |
使用全文索引
MySQL 数据库支持全文检索的查询,全文索引只能在 InnoDB 或 MyISAM 的表上使用,并且只能用于创建 char,varchar,text 类型的列。
其语法如下:
1 | MATCH(col1,col2,...) AGAINST(expr[search_modifier]) |
全文搜索使用?**MATCH() AGAINST()
**语法进行,其中,MATCH()
采用逗号分隔的列表,命名要搜索的列。AGAINST()
接收一个要搜索的字符串,以及一个要执行的搜索类型的可选修饰符。全文检索分为三种类型:自然语言搜索、布尔搜索、查询扩展搜索。
Natural Language
自然语言搜索将搜索字符串解释为自然人类语言中的短语,MATCH()
默认采用 Natural Language 模式,其表示查询带有指定关键字的文档。
1 | SELECT |
Boolean
布尔搜索使用特殊查询语言的规则来解释搜索字符串,该字符串包含要搜索的词,它还可以包含指定要求的运算符,例如匹配行中必须存在或不存在某个词,或者它的权重应高于或低于通常情况。例如,下面的语句要求查询有字符串”Pease”但没有”hot”的文档,其中+和-分别表示单词必须存在,或者一定不存在。
1 | select * from fts_test where MATCH(content) AGAINST('+Pease -hot' IN BOOLEAN MODE); |
Boolean 全文检索支持的类型包括:
+:表示该 word 必须存在
-:表示该 word 必须不存在
(no operator)表示该 word 是可选的,但是如果出现,其相关性会更高
@distance表示查询的多个单词之间的距离是否在 distance 之内,distance 的单位是字节,这种全文检索的查询也称为
Proximity Search
,如MATCH(context) AGAINST('"Pease hot"@30' IN BOOLEAN MODE)
语句表示字符串 Pease 和 hot 之间的距离需在30字节内:表示出现该单词时增加相关性
<:表示出现该单词时降低相关性
~:表示允许出现该单词,但出现时相关性为负
- :表示以该单词开头的单词,如
lik*
,表示可以是lik
,like
,likes
- :表示以该单词开头的单词,如
“ :表示短语
Query Expansion
查询扩展搜索是对自然语言搜索的修改,这种查询通常在查询的关键词太短,用户需要 implied knowledge(隐含知识)时进行,例如,对于单词 database 的查询,用户可能希望查询的不仅仅是包含 database 的文档,可能还指那些包含 MySQL、Oracle、RDBMS 的单词,而这时可以使用 Query Expansion 模式来开启全文检索的 implied knowledge。
通过在查询语句中添加 WITH QUERY EXPANSION / IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION 可以开启 blind query expansion(又称为 automatic relevance feedback),该查询分为两个阶段。
- 第一阶段:根据搜索的单词进行全文索引查询
- 第二阶段:根据第一阶段产生的分词再进行一次全文检索的查询
1 | SELECT |
删除全文索引
1、直接删除全文索引语法如下:
1 | DROP INDEX full_idx_name ON db_name.table_name; |
2、使用 alter table 删除全文索引语法如下:
1 | ALTER TABLE db_name.table_name DROP INDEX full_idx_name; |