概念
通过数值比较、范围过滤等就可以完成绝大多数我们需要的查询,但是,如果希望通过关键字的匹配来进行查询过滤,那么就需要基于相似度的查询,而不是原来的精确数值比较。全文索引就是为这种场景设计的。
你可能会说,用 like + %
就可以实现模糊匹配了,为什么还要全文索引? like + %
在文本比较少时是合适的,但是对于大量的文本数据检索,是不可想象的。全文索引在大量的数据面前,能比 like + %
快 N 倍,速度不是一个数量级,但是全文索引可能存在精度问题。
你可能没有注意过全文索引,不过至少应该对一种全文索引技术比较熟悉:各种的搜索引擎。虽然搜索引擎的索引对象是超大量的数据,并且通常其背后都不是关系型数据库,不过全文索引的基本原理是一样的。
全文索引是以词为基础的,MySQL 默认的分词是所有非字母和数字的特殊符号都是分词符(外国人嘛)。
MySQL 5.6 以前的版本,只有 MyISAM 存储引擎支持全文索引;
MySQL 5.6 及以后的版本,MyISAM 和 InnoDB 存储引擎均支持全文索引;
在MySQL 5.7.6之前,全文索引只支持英文全文索引,不支持中文全文索引,需要利用分词器把中文段落预处理拆分成单词,然后存入数据库。
从MySQL 5.7.6开始,MySQL内置了 ngram
全文解析器,用来支持中文、日文、韩文分词。
只有字段的数据类型为 char、varchar、text 及其系列才可以建全文索引。
创建全文索引
与其他类型的索引的创建方式相同,指定解析器为 ngram
时可以支持中文检索:
CREATE FULLTEXT INDEX ft_index ON articles (title,body) WITH PARSER ngram;
与全文索引有关的参数
innodb_ft_aux_table:指定包含FULLTEXT索引的InnoDB表的的名称。
innodb_ft_cache_size:创建一个InnoDB FULLTEXT索引时在内存中存储已解析文档的缓存大小。
innodb_ft_enable_diag_print:是否开启额外的全文搜索诊断输出。
innodb_ft_enable_stopword:是否开启停止字。
innodb_ft_max_token_size:存储在InnoDB的FULLTEXT索引中的最大词长。
innodb_ft_min_token_size:存储在InnoDB的FULLTEXT索引中的最小词长。
innodb_ft_num_word_optimize:为InnoDB FULLTEXT索引执行OPTIMIZE操作每次所处理的词数。
innodb_ft_server_stopword_table:含有停止字的表。
innodb_ft_sort_pll_degree:为较大的表构建搜索索引时用于索引和记号化文本的并行线程数。
innodb_ft_user_stopword_table:含有停止字的表。
innodb_optimize_fulltext_only:改变OPTIMIZE TABLE语句对InnoDB表操作的方式。
ft_boolean_syntax:改变IN BOOLEAN MODE的查询字符,不用重新启动MySQL也不用重建索引
ft_max_word_len:最长的索引字符串,默认值为84,修改后必须重建索引文件
ft_min_word_len:最短的索引字符串,默认值为4,修改后必须重建索引文件
ft_query_expansion_limit:查询括展时取最相关的几个值用作二次查询
ft_stopword_file:全文索引的过滤词文件
ngram_token_size:以 ngram 解释器搜索全文索引时,指定的搜索字符数最小字符个数(非字节),默认为 2
重建索引文件
修改参数后需要重建索引文件,否则新参数不会生效
MyISAM 引擎可以使用命令
repair table tablename quick;
InnoDB 引擎可以使用命令
optimize table tablename;
通用的方法是删除表的索引,然后重新创建
使用全文索引
语法
MATCH(col1,col2,…) AGAINST (expr[search_modifier])
MATCH:内容为已建立FULLTEXT索引并要从中查找数据的列
指定的列必须和全文索引中指定的列完全相同,否则就会报错,无法使用全文索引,这是因为全文索引不会记录关键字来自哪一列。如果想要对某一列使用全文索引,请单独为该列创建全文索引。
expr:为要查找的文本内容
search_modifier:可选搜索类型。
search_modifier 取值有四种:
IN NATURAL LANGUAGE MODE(默认):自然语言全文搜索。
IN BOOLEAN MODE:布尔全文搜索。
IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION:带查询扩展的自然语言全文搜索。
WITH QUERY EXPANSION:等同于上一个
MATCH (…) AGAINST (…)
语句实际上会计算出每行数据与查找内容的相关度,它是一个非负浮点数。该值越大表明相应的行与所查找的内容越相关,0 表明不相关。该值基于行中的单词数、行中不重复的单词数、文本集合中总单词数以及含特定单词的行数计算得出。
用法举例:
#查询相关度评分
select *,match(title) against('study' IN NATURAL LANGUAGE MODE) as score from tablename order by score desc;
#返回相关度评分不为 0 的行
select * from tablename where match(title) against('study' IN NATURAL LANGUAGE MODE);
#既看到查找结果又了解具体的相关度
select *,match(title) against('study') as score from tablename where match(title) against('study') order by score desc;
#注意: 通过在查找部分和条件部分分别使用相同的 MATCH(…) AGAINST(…) 不会增加额外开销,MySQL优化器知道两个 MATCH(…) AGAINST(..) 是相同的,只会执行一次该语句
自然语言模式
默认情况下,或者使用 in natural language mode
修饰符时,match() 函数对文本集合执行自然语言搜索
布尔模式
如果在 AGAINST() 函数中指定了 IN BOOLEN MODE 模式,则MySQL会执行布尔全文搜索。在该搜索模式下,待搜索单词前或后的一些特定字符会有特殊的含义。
+
:前导或尾随加号表示该单词必须出现在返回的每一行中。InnoDB 只支持前导加号。-
:前导或尾随的负号表示此单词在返回的任何行中均不得出现。InnoDB 仅支持前导减号。空内容
:默认情况下(既未指定+
也 未指定-
),该单词为可选,但包含该单词的行的评分较高。相当于没有IN BOOLEAN MODE
修饰符的行为@distance
:用于指定两个或多个单词相互之间的距离(以单词度量)需在指定的范围内>
:用于增加后跟单词对其所在行的相关性的贡献<
:用于降低后跟单词对其所在行的相关性的贡献()
:用于将单词分组为子表达式且可以嵌套~
:后跟单词对其所在行的相关性的贡献值为负;*
:通配符,若为单词指定了通配符,那么即使该单词过短或者出现在了停止字列表中它也不会被移除""
:括在双引号中的短语指明行必须在字面上包含指定的短语,全文搜索将短语分割为词后在 FULLTEXT 索引中搜索。非字字符无需完全匹配,如"test phrase"
可以匹配含test phrase
的行,也匹配含phrase test
的行。