全文索引

概述

​ 通过索引字段的前缀进行查找,B+树索引是支持的,利用B+树索引就可以进行快速查询。

SELECT * FROM blog WHERE content like 'xxx%';

​ 但是查询包含单词的情况,就无能为力了。所以需要进入全文检索技术Full-Test Search

select * from blog where content like '%xxx%';

​ 全文检索是将存储于数据库中的整本书或者整片文章中的任意内容信息查找出来的技术。

倒排索引

​ 全文检索通常使用倒排索引inverted index来实现。倒排索引同B+树索引一样,也是一种索引结构。它在辅助表auxiliary table中存储了单词与单词自身在一个或多个文档中所在位置之间的映射。这通常利用关联数组实现,其拥有两种表现形式:

  • invert file index:{单词,单词所在文档的ID}
  • full inverted index:{单词,(单词所在文档的ID,在具体文档中的位置)}

一个demo:

DocumentId表示进行全文检索文档的ID,Text保湿存储的内容,需要对内容进行全文检索,得到某个单词的出现过的文档ID。

​ 对于使用invert file index的关联数组,其存储内容如下,之后进行查找就简单了

​ 对于使用full inverted index的关联数组,其存储内容如下

​ 不仅存储了ID,还存储了出现的位置。空间占用更多,但是功能更强。

InnoDB全文检索

InnoDB存储引擎采用full inverted index的方式,将(DocumentIdPosition)视为一个ilist,因此在全文检索表中,有两个列,一个是word字段,另一个是ilist字段。

InnoDB存储引擎中,为了提高全文检索的并行性能,共有六张Auxiliary Table辅助表,目前每张表根据word的Latin编码进行分区。

Auxiliary Table辅助表是持久表,存放在磁盘上,使用FTS Index Cache全文检索缩进缓存,用来提高全文检索的性能。FTS Index Cache是一个红黑树结构,其根据(word, ilist)进行排序。

​ 表数据更新后,先导入到FTS Index Cache中,但是还没有更新到Auxiliary Table中。InnoDB存储引擎会批量对Auxiliary Table进行更新,而不是每次插入后更新一次Auxiliary Table

​ 当对全文检索进行查询时,Auxiliary Table首先将会在FTS Index Cache中对应的word字段合并到Auxiliary Table中,然后再进行查询。

​ 引擎允许用户查看指定倒排索引的Auxilary Table中分词的信息,可以通过设置参数innodb_ft_aux_table来观察倒排索引的Auxiliary Table

set global innodb_ft_aux_table = 'test/fts_a';

​ 设置完成后,可以通过查询information_scheme架构下的表Innodb_ft_index_table得到表fts_a的分词信息。

​ 对于InnoDB存储引擎而言,总是在事务提交时将分词写入到FTS Index Cache,然后再通过批量更新写入到磁盘。所以在数据库关闭时,会将FTS Index Cache同步到Auxiliary Table中。如果发生宕机的话,下次重启数据库时,当用户对表进行全文索引(查询或插入操作时)时,会自动读取未完成的文档,然后进行分词操作,再将分词的结果放入到FTS Index Cache中。

​ 参数innodb_ft_cache_size用来控制FTS Index Cache的大小,默认值为32M。当缓存满时,会将其中的分词信息同步到磁盘的辅助表中。增大参数可以提高全文检索的性能。但是宕机的时候,未同步到磁盘的索引信息需要更长的时间恢复。

FTS Document ID是另外一个重要的概念。为了支持全文检索,必须有一个列与word进行映射,在InnoDB存储引擎重这个列被命名为FTC_DOC_ID,其类型必须是BIGINT UNSIGNED NOT NULL,并且Innodb存储引擎自动会在该列上加入一个名为FTS_DOC_ID_INDEXUnqiue Index。上述操作都由引擎自己完成。

​ 对于删除操作,在事务提交时,只删除FTS Cache Index中的记录,对于Auxiliary Table中被删除的记录,会记录下其FTS Documont ID,并将其保存在DELETED auxiliary table中。在设置参数innodb_ft_aux_table后,用户同样可以访问information_scheme架构下的表INNODB_FT_DELETED来观察删除的FTS Document ID

​ 因为文档的DML操作实际并不删除索引中的数据,反而还会在对应的DELETED表中插入数据,因此索引会变的非常大。从所以中清理已经删除的记录,命令是OPTIMIZE TABLE。但是这个命令会进行一些其他操作,如果进希望对倒排索引进行操作,通过设置参数innodb_optimize_fulltext_only进行设置。

set global innodb_optimize_fulltext_only = 1;
optimize table fts_a;

​ 若被删除的文档非常多,那么OPTIMIZE TABLE操可能需要占用非常多的时间,会影响程序的并发性,可以设置参数innodb_ft_num_word_optimize来限制每次实际删除的分词数量。默认值为2000。

一个demo:

​ 创建表,添加全文检索

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, 'Pease porrideg in the pot'; INSERT INTO fts_a
select null, 'Pease porrideg in the hot, pease porridege cold'; INSERT INTO fts_a
select null, 'Nine days old'; CREATE FULLTEXT INDEX idx_fts ON fts_a(body);

​ 通过设置参数查看分词对应信息:

set global innodb_ft_aux_table='test/fts_a';
select * from information.innodb_ft_index_table;

​ 删除FTS_DOC_ID为3的文档。

DELETE FROM test.fts_a where fts_doc_id = 3;

​ 并不会直接删除索引中对应的数据,而是将删除的文档ID插入到DELETED表,因此可以进行查询

select * from innodb_ft_deleted;

​ 如果要彻底删除倒排索引中改文档的分词信息。执行

set global innodb_optimize_fulltext_only = 1;
optimize table test.fts_a;
select * from innodb_ft_deleted;
select * from innodb_ft_being_deleted;

​ 运行OPTIMIZE TABLE可以将记录进行彻底的删除,并且彻底删除的文档ID会记录到表INNODB_FT_BEING_DELETED中。此外,被删除的文档ID,不允许再次进行插入。

stopword列表,表示在该列表中的word不需要进行索引分词操作。默认的表在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 = "test/user_stopword";

​ INNODB全文检索的限制:

  • 每张表只嗯呢该有一个全文检索的索引
  • 由多列组合而成的全文索引列不必须使用相同的字符集与排序规则
  • 不支持没有单词界定符的语言:如中文、韩文、日文等。

全文检索

​ 语法为:

MATCH(col1, col2, ...) AGAINST (expr (serch_modifier))
search_modifier:
{
IN NATURAL LANGUAGE MODE
| IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION
| IN BOOLEAN MODE
| WITH QUERY EXPANSIONS
}
  1. Natural Language

    ​ 通过MACTH函数进行查询,默认采用的模式,表示查询带有指定word的文档。

    select * from fts_a where match(body) against('Porridge' IN NATURAL LANGUAGE MODE)
    
    select * from fts_a where match(body) against('Porridge');

    ​ 在where条件中使用MATCH函数,其返回结果是根据相关性进行降序排序的,即相关性最高的结果放在第一位。相关性的值是一个非负的浮点数字。0表示咩有任何相关行。

    ​ 相关性的计算依据的条件:

    • word是否在文档中出现
    • word在文档中出现的次数
    • word在索引列中的数量
    • 多少个文档包含该word

    通过SQL语句查看相关性:

    select fts_doc_id, body,
    Match(body) against('Porridge' IN NATURAL LANGUAGE MODE) as Relevance
    from fts_a;

    ​ INNODB存储引擎的全文检索,还需要考虑一下的因素:

    • 查询的word在stopword列中,忽略该字符串的查询
    • 查询的word的字符长度是否在区间[innodb_ft_min_token_size, innodb_ft_max_token_size]内,不在内部,忽略该字符串的查询。
  2. Boolean

    ​ 使用IN BOOLEAN MODE修饰符时,查询字符串的前后字符会有特殊的含义。例如

    #pease这个字符串一定存在但hot这个字符串不存在
    select * from fts_a
    where match(body) against ('+Pease -hot' in boolean mode)\G;

    Boolean全文索引支持以下几种操作符:

    • +表示该word必须存在

    • -表示该word必须被排除

    • (no operator)表示该word是可选的,但是如果出现,相关性会更高

    • @distance表示查询的多个单词之间的距离是否在distance之内,distance的单位是字节。这种全文检索的查询也成为Proximity Search,例如

      match(body) against ('"Pease pot"@30' IN BOOLEAN MODE)

      表示字符串Pease和hot之间的距离需要在30字节内。

    • '>'表示出现该单词增加相关性

    • '<'表示出现该单词降低相关性

    • '~'表示允许出现该单词,但是出现时相关性为负(全文检索查询允许负相关性)。

    • '*'表示以该单词开的单词

    • "表示短语。

  3. Query Expansion

    ​ 支持全文索引的扩展查询。通过在查询短语中添加WITH QUERY EXPANSIONIN NATURAL LANGUAGE MODE WITH QUERY EXPANSION可以开启bind query expansion,查询分为两个阶段:

    • 第一阶段:根据搜索的单词进行全文索引查询。
    • 第二阶段:根据第一阶段产生的分词再进行一次全文检索的查询

MySQL技术内幕读书笔记(六)——索引与算法之全文索引的更多相关文章

  1. MySQL技术内幕读书笔记(五)——索引与算法

    索引与算法 INNODB存储引擎索引概述 ​ INNODB存储引擎支持以下几种常见的索引: B+树索引 全文索引 哈希索引 ​ InnoDB存储引擎支持的哈希索引是自适应的.会根据表的情况自动添加 ​ ...

  2. MySQL技术内幕读书笔记(七)——锁

    锁 ​ 锁是数据库系统区分与文件系统的一个关键特性.为了保证数据一致性,必须有锁的介入.数据库系统使用锁是为了支持对共享资源进行并发访问,提供数据的完整性和一致性. lock与latch ​ 使用命令 ...

  3. MySQL技术内幕读书笔记(八)——事务

    事务的实现 ​ 事务隔离性由锁来实现.原子性.一致性.持久性通过数据库的redo log和undo log来完成.redo log称为重做日志,用来保证事务的原子性和持久性.undo log用来保证事 ...

  4. MySQL技术内幕读书笔记(四)——表

    目录 表 索引组织表 InnoDB逻辑存储结构 INNODB行记录格式 INNODB数据页结构 约束 视图 分区表 表 ​ 表就是关于特定实体的数据集合,是关系型数据库模型的核心. 索引组织表 ​ 在 ...

  5. MySQL技术内幕读书笔记(三)——文件

    目录 文件 参数文件 日志文件 套接字文件 pid文件 表结构定义文件 INNODB存储引擎文件 文件 ​ 有以下类型文件 参数文件:告诉MYSQL实例启动时在哪里找到数据库文件,并且制定某些初始化参 ...

  6. MySQL技术内幕读书笔记(二)——InnoDB存储引擎

    目录 InnoDB存储引擎 InnoDB存储架构 Checkpoint技术 Master Thread 工作方式 InnoDB关键特性(放一下,感觉看后面,再看总结吧) InnoDB存储引擎 Inno ...

  7. MySQL技术内幕读书笔记(一)——Mysql体系结构和存储引擎

    目录 MySQL体系结构和存储引擎 定义数据库和实例 MYSQL体系结构 MYSQL存储引擎 MySQL体系结构和存储引擎 定义数据库和实例 数据库:物理操作系统文件或者其他形式文件类型的结合.在MY ...

  8. 深入理解linux网络技术内幕读书笔记(六)--PCI层与网络接口卡

    Table of Contents 1 本章涉及的数据结构 1.1 pci_device_id结构 1.2 pci_dev结构 1.3 pci_driver结构 2 PCI NIC设备驱动程序的注册 ...

  9. Struts2技术内幕 读书笔记一 框架的本质

    本读书笔记系列,主要针对陆舟所著<<Struts2技术内幕 深入解析Strtus2架构设计与实现原理>>一书.笔记中所用的图片若无特殊说明,就都取自书中,特此声明. 什么是框架 ...

随机推荐

  1. hdu1202解题报告

    #include<stdio.h>int main(){    int n,i;    double sum,s,p,sum1;    while(scanf("%d" ...

  2. 解决资源id冲突

    --摘自<android插件化开发指南> 1.一套完整的Android App打包流程(Gradle方案) 第一步:aapt.为res目录下的资源生成R.java文件,同时为Android ...

  3. SMB溢出漏洞所需的SMB协议内容

    来一张wireshark抓下的SMB包,再解读一下. 一个包的内容有 网卡 IPV4 TCP NetBIOS SMB SMB header SMB Command: xxx Error class: ...

  4. 学习笔记——在vue中如何配置Jest(一)

    最近在搞Jest单元测试,如何在vue中安装和使用jest我就不说了,前一篇文章简单的说了一下在使用jest时遇到的一些问题,但是我觉得并没有真正的解决的很好.后面会在学习过程中更新前面的那篇文章,加 ...

  5. [洛谷P1880][NOI1995]石子合并

    区间DP模板题 区间DP模板Code: ;len<=n;len++) { ;i<=*n-;i++) //区间左端点 { ; //区间右端点 for(int k=i;k<j;k++) ...

  6. Wannafly Winter Camp 2019.Day 8 div1 I.岸边露伴的人生经验(FWT)

    题目链接 \(Description\) 给定\(n\)个十维向量\(\overrightarrow{V_i}=x_1,x_2,...,x_{10}\).定义\(\overrightarrow{V}= ...

  7. 12.7 Test

    目录 2018.12.7 Test A 序列sequence(迭代加深搜索) B 轰炸bomb(Tarjan DP) C 字符串string(AC自动机 状压DP) 考试代码 A C 2018.12. ...

  8. 转载 转载 转载 数组a[],a,&a之间的区别

    通俗理解:内存就是公寓房间,指针就是房间的门牌号,数组就是连续的公寓房间,数组名就是这组连续房间的起始地址,也就是第一个房间的地址. 例如int a[5]   a是数组名,也就是第一个房间号 & ...

  9. Html图像标签、绝对路径和相对路径:

    Html图像标签: <img>标签可以在网页上插入一张图片,它是独立使用的标签,它的常用属性有: (1)src 属性 定义图片的引用地址 (2)alt 属性 定义图片加载失败时显示的文字, ...

  10. Spring-context 实现Hello World

    Spring-context 实现Hello World 本文作为Spring入门笔记,用Spring-context实现控制台的hello world Spring简介 Spring是一个开放源代码 ...