后浪笔记一零二四

全文索引

1. 全文索引

全文索引是将数据库中文本信息中的任意内容查找出来的技术,从InnoDB 1.2版本(MySQL 5.6)开始,InnoDB开始支持全文索引,InnoDB允许在类型为char、varchar、text上建立全文索引。

下列语句会常见一个表essay并给content字段加上全文索引:

1
CREATE table essay (id int auto_increment primary key, title varchar(255), content text, fulltext(content))

创建该表后,InnoDB会在数据文件目录创建以下文件:

essay.frm
essay.ibd
FTS_000000000000006b_00000000000000d3_INDEX_1.idb
FTS_000000000000006b_00000000000000d3_INDEX_2.idb
FTS_000000000000006b_00000000000000d3_INDEX_3.idb
FTS_000000000000006b_00000000000000d3_INDEX_4.idb
FTS_000000000000006b_00000000000000d3_INDEX_5.idb
FTS_000000000000006b_00000000000000d3_INDEX_6.idb
FTS_000000000000006b_BEING_DELETED.ibd
FTS_000000000000006b_BEING_DELETED_CACHE.ibd
FTS_000000000000006b_CONFIG.ibd
FTS_000000000000006b_DELETED.ibd
FTS_000000000000006b_DELETED_CACHE.ibd

2.1 全文索引的使用:

InnoDB(还有MyISAM)的全文索引支持三种模式:

  1. 自然语言模式:通过MATCH AGAINST传递一个关键字(字符串)进行检索,例如:
1
select * from essay where match(content) against('Faraday' in natural language mode)
  1. 布尔模式:为检索的字符串增加一个操作符
+ 表示必须包含
- 表示必须不包含
> 表示出现该字符串时增加相关性
< 表示出现该字符串时降低相关性
* 表示通配符
~ 表示允许出现该单词,但是出现时相关性为负
""表示短语

例如:

1
select title from essay where match(content) against('+Faraday -Davy >Sir' in boolean mode);
  1. 查询扩展模式:查询关键字太短,需要implied knowledge时才能进行。比如查询的关键字是search engine,用户可能希望得到的是google、baidu、bing这类的关键字

2.2 全文索引实现机制

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

  • inverted file index,其表现形式为【单词,单词所在文档ID】
  • full inverted index,其表现形式为【单词,【单词所在文档ID,在具体文档中的位置】】

为什么称之为倒排索引呢,因为一般的索引的表现形式是【单词所在文档,单词】,即文档->单词的映射,而倒排索引是相反的,通过关键字找到所在文档可以提高查询效率。

full inverted index相比inverted file index占用了更多的空间,但是能够更好地定为数据,并扩充一些其他的搜索特性。InnoDB采用的就是full inverted index的形式:

Text(word) Document(FTS_DOC_ID:Position)
China (1:2),(5:6)
Japan (3:4),(8:9)
France (7:8)

在InnoDB存储引擎中,将【单词所在文档ID,在具体文档中的位置】视为一个ilist,因此在全文检索的表中具有两个列:一个是word字段,另外一个是ilist字段(键值对结构,键为FTS_DOC_ID,值为在文档中的位置),并在word字段上设置索引。保存word字段的表称之为辅助表(Auxiliary Table),默认有六张,也就是上述示例的FTS_000000000000006b_00000000000000d3_INDEX_1.idbFTS_000000000000006b_00000000000000d3_INDEX_6.idb文件,这也就意味着辅助表会持久化到磁盘上。

为了提高辅助表的性能,InnDB实现了全文检索索引缓存(FTS Index Cache),用来提高全文索引的功能。FTS Index Cache是一个红黑树结构,根据(word, ilist)进行排序。也就是说,在事务提交后,全文索引的更新操作可能在分词操作后还在FTS Index Cache中,辅助表可能还没有更新,InnoDB采用了一种批量对辅助表进行更新的策略,而不是每次在插入文档后就更新辅助表。当客户端进行全文检索时,辅助表首先会在FTS Index Cache中对应的word字段合并到辅助表中,然后再进行查询。当数据库关闭时,FTS Index Cache中的数据库会同步到磁盘上的辅助表中,当数据库宕机时,在下次启动数据库的时候InnoDB会自动读取未完成的文档并进行分词操作,再将其结果存入TTS Index Cache

上面这种操作类似于Insert Buffer,只不过Insert Buffer可以持久化为页,并且是B+树结构。参数innodb_ft_cache_size可以控制FTS Index Cache的大小,默认为32MB,增大该参数可以提高全文索引的性能,但在发生宕机时恢复时间会变长。

刚才提到的FTS_DOC_ID也是一个重要的概念,为了支持全文索引,必须有一个列与word进行映射,这个列就是FTS_DOC_ID,这个列的类型为BIGINT UNSIGNED NOT NULL,并且会自动给这个列加上UNIQUE索引。

对于文档的删除操作,在事务提交后,不会删除辅助表中的记录,而只是删除FTS Index Cache中的记录。对于辅助表中被删除的记录,InnoDB会记录下FTS_DOC_ID,并保存在DELETED辅助表中。由于文档的DML操作不会删除索引中的记录,反而会在DELETED辅助表(即上述示例的FTS_000000000000006b_DELETED.ibd文件)中插入记录,因此索引会变得越来越大。InnoDB允许用户手动将已经删除的文档从索引中彻底删除,这个命令就是OPTIMIZE TABLE,如果删除的文档非常多,那么这个命令可能需要占用很多时间,影响其他用户的响应时间,所以用户还可以通过参数innodb_ft_num_word_optimize来限制每次执行该命令时删除的分词数量,这个值默认是2000。

对于文档的查询操作,步骤为:

  1. 根据用户搜索符合条件的TFS_DOC_ID,再检索DELETED表中记录的FTS_DOC_ID,这些记录将会被过滤使用
  2. 根据FTS_DOC_ID找到对应的文档,并按照相关性对结果集进行降序排序。

专题:

本文发表于 2022-07-01,最后修改于 2022-07-01。

本站永久域名「 jiavvc.top 」,也可搜索「 后浪笔记一零二四 」找到我。


上一篇 « 问题 下一篇 » 乐观锁和悲观锁

赞赏支持

请我吃鸡腿 =^_^=

i ysf

云闪付

i wechat

微信

推荐阅读

Big Image