InnoDB全文索引
### 如果想了解全文索引,可以直接将本文复制到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全文索引的更多相关文章
- 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 ...
- MySQL全文索引 FULLTEXT索引和like的区别
1.概要 InnoDB引擎对FULLTEXT索引的支持是MySQL5.6新引入的特性,之前只有MyISAM引擎支持FULLTEXT索引.对于FULLTEXT索引的内容可以使用MATCH()-AGAIN ...
- mysql基础语法之(全文索引)
1.概要 InnoDB引擎对FULLTEXT索引的支持是MySQL5.6新引入的特性,之前只有MyISAM引擎支持FULLTEXT索引.对于FULLTEXT索引的内容可以使用MATCH()…AGAIN ...
- InnoDB FULLTEXT
1.概要 InnoDB引擎对FULLTEXT索引的支持是MySQL5.6新引入的特性,之前只有MyISAM引擎支持FULLTEXT索引.对于FULLTEXT索引的内容可以使用MATCH()…AGAIN ...
- InnoDB INFORMATION_SCHEMA FULLTEXT Index Tables
InnoDB INFORMATION_SCHEMA FULLTEXT Index Tables 下表提供了FULLTEXT索引的元数据: mysql> SHOW TABLES FROM INFO ...
- [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优 ...
- MySQL 5.7 学习:新增配置参数
背景: 继上次介绍 初识 MySQL 5.6 新功能.参数完之后,刚好MySQL 5.7又GA了,在官方测试里看到,MySQL5.7在功能.性能.可用性.安全和监控上又提升了很高.现在看看和MySQL ...
- MySQL 5.7 学习:功能性能的提升
背景: 继上次介绍 初识 MySQL 5.6 新功能.参数完之后,刚好MySQL 5.7又GA了,在官方测试里看到,MySQL5.7在功能.性能.可用性.安全和监控上又提升了很高.现在看看和MySQL ...
- MySQL5.6新特性
Innodb加强项 1.Innodb全文索引 mysql> show create table film_text\G . row *************************** Tab ...
随机推荐
- 利用python批量修改word文件名的方法示例
利用python批量修改word文件名的方法示例 最近不小心把硬盘给格式化了,由于当时的文件没有备份,所以一下所有的文件都没有了,于是只能采取补救措施,用文件恢复软件恢复了一部分的数据出来,但是恢复完 ...
- MySQL从.ibd文件中恢复数据
首先,在MySQL命令行下执行如下命令可以查看MySQL中存放数据的位置: show global variables like "%datadir%"; 我这里的执行结果: +- ...
- DSP6455的EMIFA口
DSP6455的EMIFA口 声明:引用请注明出处http://blog.csdn.net/lg1259156776/ 支持两种不同的接口模式: 异步接口:标准的SRAM,ROM接口 同步接口:SBS ...
- vue的依赖注入provide和inject
一.解决的场景问题: 根父组件A有一个方法getMap,该组件A下的所有子组件B,子组件C,子组件D,或者子组件B下的子组件E等层层嵌套情况下,在某种情况下,都需要访问父组件的getMap方法,那么常 ...
- ByteDance面试
1.HashMap.HashSet源码解读 2.Http状态码.包头内容有哪些 响应头 说明 示例 状态 Access-Control-Allow-Origin 指定哪些网站可以跨域源资源共享 Acc ...
- RH124-3 目录结构_转
在linux里安装的时候,是可以指定某分区装在某文件夹里 目录意义 /bin 存放命令,不可以在装系统单独挂载分区 /home /dev 存放硬件设备 不可以单独挂载分区 /boot 500M 和系统 ...
- go打印九九乘法表
package main import ( "fmt" ) func main() { for i := 1; i < 10; i++ { for j := 1; j < ...
- mysql 数据库批量刷新表字段数据
UPDATE a,bSET b.studentno = a.studentnumber WHERE b.studentno IS NULL AND a.p_id = b.p_id
- 日常工作问题解决:centos7下配置网卡以及查询网卡UUID
目录 1.配置网卡 1.1 网卡查看命令:ifconfig -a 1.2 网卡配置文件说明 1.3 重启网络服务 2.查看确认网卡UUID 2.1 网卡配置文件正常时 2.2 网卡配置文件不可用或者配 ...
- java日志框架系列(4):logback框架xml配置文件语法
1.xml配置文件语法 由于logback配置文件语法特别灵活,因此无法用DTD或schema进行定义. 1.配置文件基本结构 配置文件基本结构:以<configuration>标签开头, ...