从零开始学习MySQL全文索引

1、为何要用全文索引

咱们在用一个东西前,得知道为何要用它,使用全文索引无非有如下缘由mysql

  1. like查询太慢、json字段查询太慢(车太慢了)
  2. 没时间引入ElasticSearch、Solr或者Sphinx这样的软件,或者根本就不会用(没法将五菱宏光换成兰博基尼,即便有兰博基尼也不会开)
  3. 加索引、联合索引啥的都已经慢得不行了(限速80,车顶盖都卸了也只能开到30)
  4. 为了提高一下本身的逼格(人家问你有没有开过法拉利,你说开过确定更有气质一点)

2、什么是全文索引

简单的说,全文索引就至关于大词典中的目录,经过查询目录能够快速定位到想看的内容。
全文索引经过创建倒排索引来快速匹配文档(仅在mysql5.6版本以上支持)
全文索引将连续的字母、数字和下划线当作一个单词,分割单词通常用空格/逗号/句号
MySQL的全文索引支持如下3种查询模式:sql

  1. 天然语言模式(IN NATURAL LANGUAGE MODE
    经过MATCH AGAINST 传递某个特定的字符串来进行检索
  2. 布尔模式(IN BOOLEAN MODE
    支持操做符,例如+表示包含,-表示不包含
  3. 扩展模式(WITH QUERY EXPANSION
    至关于天然语言模式下的一个扩展,执行两次检索,第一次使用给定短语检索,第二次是结合第一次相关性比较高的行进行检索.

更多请看:官方文档数据库

下面教你们如何建立全文索引,并建立测试数据演示三种查询模式的使用json

3、如何建立全文索引

  • 方式一:建表时指定
CREATE TABLE light_weight_baby ( 
    id INT AUTO_INCREMENT NOT NULL PRIMARY KEY, 
    title VARCHAR(200), 
    content TEXT, 
    FULLTEXT(title, content) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
  • 方式二:ALTER添加
ALTER TABLE table_name ADD FULLTEXT INDEX index_name (column1,column2,...);
  • 方式三:CRATE INDEX添加
CREATE FULLTEXT INDEX index_name ON table_name (column1,column2,...);

4、建立测试数据

建立一个数据库用来演示这三种模式下的检索mysql优化

CREATE DATABASE chenqionghe DEFAULT CHARSET utf8;

建立一个文章表并插入测试数据app

CREATE TABLE articles (
    id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
    title VARCHAR(200),
    body TEXT,
    FULLTEXT (title,body)
) ENGINE=InnoDB;

插入测试数据dom

INSERT INTO articles (title,body) VALUES
    ('MySQL Tutorial','DBMS stands for DataBase ...'),
    ('How To Use MySQL Well','After you went through a ...'),
    ('Optimizing MySQL','In this tutorial we will show ...'),
    ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),
    ('MySQL vs. YourSQL','In the following database comparison ...'),
    ('MySQL Security','When configured properly, MySQL ...');

执行结果以下
测试

5、查询-使用天然语言模式

这是MySQL的默认查询模式,简单示例以下优化

SELECT * FROM articles
    WHERE MATCH (title,body)
    AGAINST ('database' IN NATURAL LANGUAGE MODE);

能够看到,不区分大小写,title或body包含database的都返回了,另外,返回的结果将以相关性进行排序。

相关性:根据行中的字段、惟一单词的数量、集合中单词总数和包含特定单词的行数计算。

下面经过两种方式统计数量

# 第一种方式
 SELECT COUNT(*) FROM articles
    WHERE MATCH (title,body)
    AGAINST ('database' IN NATURAL LANGUAGE MODE);
# 第二种方式
SELECT
   COUNT(IF(MATCH (title,body) AGAINST ('database' IN NATURAL LANGUAGE MODE), 1, NULL))
    AS count
    FROM articles;

第一种作了一些额外的工做(按相关性对结果进行排序),但也能使用索引进行查询。
第二种执行了全表扫描,若是搜索项出如今大多数行中,可能比索引查询更快
匹配少数行,第一种快,匹配大多数行,第二种快

下面演示如何检索相关性,但不会进行排序(由于不包含WHEREORDER BY

SELECT id, MATCH (title,body)
     AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE) AS score
    FROM articles;

下面的示例更复杂,返回倒序后的相关性值,分别在SELECT和WHERE语句中使用了MATCH,可是不会致使额外的开销,由于mysql优化器注意到两次MATCH是相同的,只会使用一次全文搜索

SELECT id, body, MATCH (title,body) AGAINST
    ('Security implications of running MySQL as root'
    IN NATURAL LANGUAGE MODE) AS score
    FROM articles WHERE MATCH (title,body) AGAINST
    ('Security implications of running MySQL as root'
    IN NATURAL LANGUAGE MODE);

包含在("")中字符中的会被分解为单词,而后在全文索引中进行搜索,简单的说,就是进行OR查询。

6、查询-使用布尔模式(强大的语法)

使用布尔模式须要指定IN BOOLEAN MODE,不会自动根据相关性排序,一些字符具备特殊的含义,例如能够经过+或-表示一个单词必须存在或不存在。
下面的sql语句表明查询必须 包含MySQL但不包含YourSQL

SELECT * FROM articles WHERE MATCH (title,body)
    AGAINST ('+MySQL -YourSQL' IN BOOLEAN MODE);

语法

  • +
    必须出现
  • -
    必须不出现。
    注意:这个操做符是用来排除其余操做符的结果,若是只指定这个,将什么都不返回
  • 无符号
    默认状况,表明或,自动分词搜索。和没有指定IN BOOLEAN MODE的结果同样
  • @distance
    用来测试两个或两个以上的单词是否都在一个指定的距离内,在@距离前指定双引号中的搜索词,例如MATCH(col1) AGAINST('"word1 word2 word3" @8' IN BOOLEAN MODE
  • >
    提升该条匹配数据的权重值
  • <
    下降该条匹配数据的权重值
  • ()
    至关于表达式分组,和咱们数学中的表达式一个道理
  • ~
    将其相关性由正转负,表示拥有该字会下降相关性,例如+apple ~macintosh 先匹配apple,但若是同时包含macintosh,排名会靠后
  • *
    通配符,只能在字符串后面使用
  • "
    彻底匹配,被双引号包起来的单词必须整个被匹配

示例

  • apple banana
    包含apple或banana其中一个
  • +apple +juice
    必须同时包含apple和juice
  • +apple macintosh
    包含apple,可是若是同时包含macintosh会给更高的排序
  • +apple -macintosh
    包信apple可是不包含macintosh
  • +apple ~macintosh
    包含apple,若是同时包含macintosh下降权重
  • +apple +(>turnover <strudel)
    1.包含apple和turnover,或,包含apple和strudel
    2.包含apple和turnover权重高于包含apple和strudel的记录
  • apple*
    包含apple单词的行, “apple”, “apples”, “applesauce”, “applet”都会被匹配到
  • "some words"
    彻底匹配some words的行,例如 “some words of wisdom”能匹配但“some noise words”匹配不到

7、查询-使用扩展模式

当搜索短语很短时很是有用,例如搜索database可能意味着MySQL、Oracle、DB二、RDBMS都要被匹配到,这就是这个模式能作的。
添加WITH QUERY EXPANSIONIN NATURAL LANGUAGE MODE WITH QUERY EXPANSION启用,它会执行两次检索,第一次使用给定短语检索,第二次是结合第一次相关性比较高的行进行检索。
例以下面的例子

# 天然语言模式
SELECT * FROM articles
     WHERE MATCH (title,body)
    AGAINST ('database' IN NATURAL LANGUAGE MODE);

# 扩展模式
SELECT * FROM articles
    WHERE MATCH (title,body)
    AGAINST ('database' WITH QUERY EXPANSION);

能够看到第二条语句找到了包含MySQL的行,即便该行不包含database,可是由于在第一次的搜索中搜索引擎判断MySQL和database的相关性比较高,因此在执第二次搜索的时候返回了。

8、注意事项

  1. 只能在类型为CHAR、VARCHAR或者TEXT的字段上建立全文索引
  2. MATCH (字段) AGAINST (关键词),必须和建立时的字段一块儿,例如MATCH (light,weight,baby)使用的字段名与全文索引muscle(light,weight,baby)定义的字段名一致。若是只对单个字段查询,须要分别建立全文索引
  3. 全文索引是以词为基础的,innodb_ft_min_token_sizeinnodb_ft_max_token_size用来设置单词的最大和最小长度,不在这个长度区间的将忽略。
  4. 在停用词stopwords中的将被忽略
  5. 若是要导入大量数据,先导入数据再建全文索引,比先建全文索引再导入数据的方式快不少。
  6. 在MySQL 5.7.6以前,全文索引只支持英文全文索引,不支持中文全文索引,MySQL 5.7.6后内置了ngram全文解析器,支持中文、日文、韩文分词。
相关文章
相关标签/搜索