### 如果想了解全文索引,可以直接将本文复制到mysql的新建查询中,依次执行,即可了解全文索引的相关内容及特性。

-- InnoDB全文索引

-- 建表
CREATE TABLE fts_a (
FTS_DOC_ID BIGINT UNSIGNED AUTO_INCREMENT NOT NULL,
body TEXT,
PRIMARY KEY(FTS_DOC_ID)
); -- 插入数据
INSERT INTO fts_a
SELECT NULL, 'Please poorridge in the pot';
INSERT INTO fts_a
SELECT NULL, 'Please poorridge hot, pease porridge cold';
INSERT INTO fts_a
SELECT NULL, 'Nine days old';
INSERT INTO fts_a
SELECT NULL, 'Some like it hot, some like it cold';
INSERT INTO fts_a
SELECT NULL, 'Some like it in the pot';
INSERT INTO fts_a
SELECT NULL, 'Nine days old';
INSERT INTO fts_a
SELECT NULL, 'I like code days'; -- 建立全文索引
CREATE FULLTEXT INDEX idx_fts ON fts_a(body); -- 创建完成后观察表fts_a中数据
SELECT * FROM fts_a; -- 通过设置参数innodb_ft_aux_table来查看分词对应的信息
SET GLOBAL innodb_ft_aux_table="mytest/fts_a"; -- 查看分词对应的信息
SELECT * FROM information_schema.INNODB_FT_INDEX_TABLE; -- 每个word都对应一个DOC_ID 和 POSITION, (7,7)第一个7代表了第7个文档的,第二个7代表在文档中的起始位置
-- 除此之外还有FIRST_DOC_ID, LAST_DOC_ID, DOC_COUNT 分别代表了该word第一次出现的文档ID,最后一次出现的文档ID,以及该word一共在多少个文档中存在。 -- 此时我们删除ID为7的文档
DELETE FROM mytest.fts_a WHERE FTS_DOC_ID=7; -- 此时再次查看分词对应的信息,发现分词信息未发生变化
SELECT * FROM information_schema.INNODB_FT_INDEX_TABLE; -- 这是因为InnoDB并不会直接删除索引中对应的记录,而是将删除的文档ID插入到DELETED表,因此我们进行如下查询:
SELECT * FROM information_schema.INNODB_FT_DELETED; -- 可以看到删除的文档ID已经插入到了INNODB_FT_DELETED表中,这样看将来索引只会越来越多而不会减少,如果想要彻底删除倒排索引中该文档的分词信息,可以执行如下操作: -- 设置此参数为1,将仅进行倒排索引的操作,否则还会对Cardinality重新统计等其它操作
SET GLOBAL innodb_optimize_fulltext_only=1; -- 彻底删除索引
OPTIMIZE TABLE mytest.fts_a;
-- 此时第三次查看分词对应的信息,发现分词信息已经更新
SELECT * FROM information_schema.INNODB_FT_INDEX_TABLE;
-- 但是,INNODB_FT_DELETED中的记录仍在:
SELECT * FROM information_schema.INNODB_FT_DELETED;
-- 并且,会将彻底删除的文档ID记录到表INNNODB_FT_BEING_DELETED中。
SELECT * FROM information_schema.INNODB_FT_BEING_DELETED;
-- 并且不允许再次插入这个文档ID,否则数据库会异常 // Invalid InnoDB FTS Doc ID
INSERT INTO fts_a
SELECT 7, 'I like code days'; -- 还有一个概念,stopword列表,该列表中的word不需要进行索引分词操作。比如 the 这个单词没有实际意义,故不进行分词。
-- InnoDB有一张默认的stopword表,在information_schema架构下,表名为INNODB_FT_DEFAULT_STOPWORD, 默认共有36个stopword。
-- 你也可以通过参数innodb_ft_server_stopword_table来自定义stopword列表,如:
CREATE TABLE user_stopword(
value VARCHAR(30)
) ENGINE = INNODB; SET GLOBAL innodb_ft_server_stopword_table="mytest/user_stopword"; -- 当前InnoDB的全文索引还存在以下限制:v5.6
-- 每张表只能有一个全文检索的索引
-- 由多列组合而成的全文检索的索引列必须使用相同的字符集与排序规则
-- 不支持没有单词界定符的语言,如中文、日语、韩语 -- 全文检索的使用1(Natural Language) -- 普通查询
SELECT * FROM fts_a WHERE body LIKE '%Please%'; -- explain查看 type ALL
-- 使用全文检索,根据相关性进行降序排序(如果未建立全文索引,使用下面两条语句会抛出异常can't find FULLTEXT)
SELECT * FROM fts_a WHERE MATCH(body) AGAINST('porridge' IN NATURAL LANGUAGE MODE); -- explain查看 type fulltext
SELECT * FROM fts_a WHERE MATCH(body) AGAINST('porridge'); -- IN NATURAL LANGUAGE MODE 是默认模式,可以省略
-- 你会发现FTS_DOC_ID为2 的排在第一位,这是由于porridge在文档2中出现了2次,具有更高的相关性
-- 相关性四个条件:
-- word是否在文档中出现
-- word在文档中出现的次数
-- word在索引列中的数量
-- 多少个文档包含该word -- 统计MATCH函数得到的结果数量
SELECT count(*) FROM fts_a WHERE MATCH(body) AGAINST ('Porridge' IN NATURAL LANGUAGE MODE);
SELECT COUNT(IF(MATCH (body) AGAINST ('Porridge' IN NATURAL LANGUAGE MODE), 1, NULL)) AS count FROM fts_a;
-- 以上两个SQL,从内部运行来看第二个执行的可能更快些,因为第一条还需要进行相关性的排序统计。 -- 查看相关性
SELECT FTS_DOC_ID, body, MATCH(body) AGAINST('Porridge' IN NATURAL LANGUAGE MODE) AS Relevance FROM fts_a;
-- 但是对于在stopword表中的单词是查询不到相关性的
SELECT FTS_DOC_ID, body, MATCH(body) AGAINST('the' IN NATURAL LANGUAGE MODE) AS Relevance FROM fts_a;
-- 另外参数 innodb_ft_min_token_size和innodb_ft_max_token_size控制查询字符的长度,小于最小值,大于最大值的都会忽略改词的搜索。
-- 最小值默认为3,最大值默认为84 -- 全文检索的使用2(Boolean)
-- 下面的SQL返回有please或有hot的文档
SELECT * FROM fts_a WHERE MATCH(body) AGAINST('Please hot' IN BOOLEAN MODE);
-- +号表示必须存在
SELECT * FROM fts_a WHERE MATCH(body) AGAINST('+Please +hot' IN BOOLEAN MODE);
-- -号表示一定不存在
SELECT * FROM fts_a WHERE MATCH(body) AGAINST('+Please -hot' IN BOOLEAN MODE);
-- (no operator) 表示该word是可选的, 但是如果出现, 其相关性会更高
-- @distance 表示查询的多个单词之间的距离是否在distance之内,distance的单位是字节。这种全文检索的查询也称为Proximity Search。如MATCH(body) AGAINST('"Please pot"@30' IN BOOLEAN MODE) 表示字符串Please和pot之间的距离需在30字节内。
SELECT FTS_DOC_ID, body FROM fts_a WHERE MATCH(body) AGAINST('"Please pot" @30' IN BOOLEAN MODE);
SELECT FTS_DOC_ID, body FROM fts_a WHERE MATCH(body) AGAINST('"Please pot" @5' IN BOOLEAN MODE);
SELECT FTS_DOC_ID, body FROM fts_a WHERE MATCH(body) AGAINST('"Please pot" @4' IN BOOLEAN MODE);
SELECT FTS_DOC_ID, body FROM fts_a WHERE MATCH(body) AGAINST('"hot Porridge" @2' IN BOOLEAN MODE);
SELECT FTS_DOC_ID, body FROM fts_a WHERE MATCH(body) AGAINST('"Please Pease" @3' IN BOOLEAN MODE);
-- 在5.7.17版本下,经过上面的几个SQL测试,仅英文时,distance单位是4个字符(字节),即distance为2时,可以间隔8个字符(字节)
-- > 表示出现该单词时增加相关性, 增加1
SELECT FTS_DOC_ID,body, MATCH(body) AGAINST('like pot' IN BOOLEAN MODE) AS Relevance FROM fts_a;
SELECT FTS_DOC_ID,body, MATCH(body) AGAINST('like >pot' IN BOOLEAN MODE) AS Relevance FROM fts_a;
-- < 表示出现该单词时降低相关性 减少0.4左右, 可以减至负数
SELECT FTS_DOC_ID,body, MATCH(body) AGAINST('like >pot <some' IN BOOLEAN MODE) AS Relevance FROM fts_a;
-- ~ 表示允许出现该单词,但是出现时相关性为负(全文检索查询允许负相关性)。
-- * 表示以该单词开头的单词,如lik*, 表示可以是lik、like,又或者likes。
SELECT * FROM fts_a WHERE MATCH(body) AGAINST('po*' IN BOOLEAN MODE);
-- " 表示短语,而不加双引号,表示有please或有hot的文档
INSERT INTO fts_a SELECT NULL, 'Please hot tea to me';
SELECT * FROM fts_a WHERE MATCH(body) AGAINST('"Please hot "' IN BOOLEAN MODE); -- 短语不可分割
SELECT * FROM fts_a WHERE MATCH(body) AGAINST('Please hot ' IN BOOLEAN MODE); -- 全文检索的使用3(Query Expansion)
-- MySQL还支持全文检索的扩展查询。这种查询通常是在查询的关键词太短,用户需要implied knowledge(隐含知识)时进行。对于单词database的查询,用户可能希望查询的不仅仅是包含database的文档,可能还包含MySQL、Oracle、DB2、RDBMS的单词。而这时可以使用Query Expansion 模式来开启全文检索的implied knowledge。
-- 通过在查询短语中添加 WITH QUERY EXPANSION 或 IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION 可以开启blind query expansion(又称为automatic relevance feedback)。该查询分为两个阶段。
-- 第一阶段:根据搜索的单词进行全文索引查询
-- 第二阶段:根据第一阶段产生的分词再进行一次全文检索的查询。
-- 来看一个具体的例子,创建表articles:
CREATE TABLE articles (
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
title VARCHAR(200),
body TEXT,
FULLTEXT (title, body) ) ENGINE=InnoDB; 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...'),
('Tuning DB2', 'For IBM database ...'),
('IBM History', 'DB2 history for IBM ...');
-- 在这个表中并没有显式创建FTS_DOC_ID列, 因此InnoDB会自动创建该列,并添加唯一索引,
-- 此外,表articles的全文检索索引是根据列title和body的联合索引
-- 接着根据database关键字进行的全文检索查询。 -- 使用扩展查询与使用 NATURAL查询的区别。
SELECT * FROM articles WHERE MATCH(title, body) AGAINST('database' IN NATURAL LANGUAGE MODE); -- 3个文档
SELECT * FROM articles WHERE MATCH(title, body) AGAINST('database' WITH QUERY EXPANSION); -- 8个文档

InnoDB全文索引的更多相关文章

  1. InnoDB全文索引:N-gram Parser【转】

    本文来自:http://mysqlserverteam.com/innodb%E5%85%A8%E6%96%87%E7%B4%A2%E5%BC%95%EF%BC%9An-gram-parser/ In ...

  2. MySQL全文索引 FULLTEXT索引和like的区别

    1.概要 InnoDB引擎对FULLTEXT索引的支持是MySQL5.6新引入的特性,之前只有MyISAM引擎支持FULLTEXT索引.对于FULLTEXT索引的内容可以使用MATCH()-AGAIN ...

  3. mysql基础语法之(全文索引)

    1.概要 InnoDB引擎对FULLTEXT索引的支持是MySQL5.6新引入的特性,之前只有MyISAM引擎支持FULLTEXT索引.对于FULLTEXT索引的内容可以使用MATCH()…AGAIN ...

  4. InnoDB FULLTEXT

    1.概要 InnoDB引擎对FULLTEXT索引的支持是MySQL5.6新引入的特性,之前只有MyISAM引擎支持FULLTEXT索引.对于FULLTEXT索引的内容可以使用MATCH()…AGAIN ...

  5. InnoDB INFORMATION_SCHEMA FULLTEXT Index Tables

    InnoDB INFORMATION_SCHEMA FULLTEXT Index Tables 下表提供了FULLTEXT索引的元数据: mysql> SHOW TABLES FROM INFO ...

  6. [MySQL Reference Manual] 8 优化

    8.优化 8.优化 8.1 优化概述 8.2 优化SQL语句 8.2.1 优化SELECT语句 8.2.1.1 SELECT语句的速度 8.2.1.2 WHERE子句优化 8.2.1.3 Range优 ...

  7. MySQL 5.7 学习:新增配置参数

    背景: 继上次介绍 初识 MySQL 5.6 新功能.参数完之后,刚好MySQL 5.7又GA了,在官方测试里看到,MySQL5.7在功能.性能.可用性.安全和监控上又提升了很高.现在看看和MySQL ...

  8. MySQL 5.7 学习:功能性能的提升

    背景: 继上次介绍 初识 MySQL 5.6 新功能.参数完之后,刚好MySQL 5.7又GA了,在官方测试里看到,MySQL5.7在功能.性能.可用性.安全和监控上又提升了很高.现在看看和MySQL ...

  9. MySQL5.6新特性

    Innodb加强项 1.Innodb全文索引 mysql> show create table film_text\G . row *************************** Tab ...

随机推荐

  1. Linux (Ubuntu)安装ssh

    看ssh服务是否启动 打开"终端窗口",输入sudo ps -e |grep ssh 回车有sshd,说明ssh服务已经启动, 如果没有启动,输入sudo service ssh ...

  2. docker安装并持久化postgresql数据库

    安装docker步骤略过 1.拉取postgresql镜像 docker pull postgresql 2.创建本地卷,数据卷可以在容器之间共享和重用, 默认会一直存在,即使容器被删除(docker ...

  3. Npcap.资料

    1.ZC:Npcap 是 WinPcap停更之后的继承者.我尝试了 Win7中发送raw tcp syn,它的代码和 使用WinPcap的基本一致. Developing software with ...

  4. vue告警信息:{ parser: "babylon" } is deprecated.

    告警信息: 13% building modules 28/40 modules 12 active ...dex=0!\src\App.vue{ parser: "babylon" ...

  5. luoguP1463:反素数ant(打表心得☆)

    题目描述 对于任何正整数x,其约数的个数记作g(x).例如g()=.g()=. 如果某个正整数x满足:g(x)>g(i) <i<x,则称x为反质数.例如,整数1,,,6等都是反质数. ...

  6. springboot集成webSocket能启动,但是打包不了war

    1.pom.xml少packing元素 https://www.cnblogs.com/zeussbook/p/10790339.html 2.SpringBoot项目中增加了WebSocket功能无 ...

  7. CentOS7.5下安装nginx --项目部署

    1.安装ngnix一些依赖包 [root@VM_39_157_centos ~]# yum -y install gcc gcc-c++ openssl-devel pcre-devel httpd- ...

  8. K8S从入门到放弃系列-(2)集群根证书准备

    k8s从1.8版本开始,集群中各个组件需要使用TLS证书对通信进行加密,每个k8s集群都需要有独立的CA证书体系,这里我们采用比较常用的CloudFlare 的 PKI 工具集 cfssl 来生成 C ...

  9. Jmeter 跨线程组传递参数 之两种方法(转)

    终于搞定了Jmeter跨线程组之间传递参数,这样就不用每次发送请求B之前,都需要同时发送一下登录接口(因为同一个线程组下的请求是同时发送的),只需要发送一次登录请求,请求B直接用登录请求的参数即可,直 ...

  10. Java中的静态导入

    Java从1.5开始,增加了静态导入的语法,静态导入使用import static语句,分为两种: 导入指定类的某个静态成员变量.方法. 导入指定类的全部的静态成员变量.方法. 下面是代码演示: /* ...