整体理解的索引召回结构:段(segment文件)-词项索引(FST内存)- 找到词典可能所在的块 - 词典(字典序文件)、倒排表(posting list文件、跳表查找)-bool运算
https://blog.csdn.net/weixin_38289303/article/details/109399137
倒排查询逻辑
在介绍了索引表和记录表的结构后,就可以得到 Lucene 倒排索引的查询步骤:
通过 Term Index 数据(.tip文件)中的 StartFP 获取指定字段的 FST通过 FST 找到指定 Term 在 Term Dictionary(.tim 文件)可能存在的 Block将对应 Block 加载内存,遍历 Block 中的 Entry,通过后缀(Suffix)判断是否存在指定 Term存在则通过 Entry 的 TermStat 数据中各个文件的 FP 获取 Posting 数据如果需要获取 Term 对应的所有 DocId 则直接遍历 TermFreqs,如果获取指定 DocId 数据则通过 SkipData 快速跳转
Term Dictionary(简单理解:field字典)
例如字典序排序之后就变成了:
Ada,Carla,Elin,Kate,Patty,Sara,Selena
这样我们可以用二分查找的方式,比全遍历更快地找出目标的 term。这个就是 term dictionary。有了 term dictionary 之后,可以用 logN 次磁盘查找得到目标。
Term Index倒排词典的索引是常驻内存的
想想为啥不用 HashMap,HashMap 也能实现有序Map?耗内存啊!牺牲了一点性能来节约内存,旨在把所有Term Index都放在内存里面,最终的效果是提升了速度,否则hashmap无法支持各种分词后的模糊搜索。如上可知,FST是压缩字典树后缀的图结构,她拥有Trie高效搜索能力,同时还非常小。这样的话我们的搜索时,能把整个FST加载到内存。
“为什么 Elasticsearch/Lucene 检索可以比 mysql 快“。Mysql 只有 term dictionary 这一层,是以 b-tree 排序的方式存储在磁盘上的。检索一个 term 需要若干次的 random access 的磁盘操作。而 Lucene 在 term dictionary 的基础上添加了 term index 来加速检索,term index 以树的形式缓存在内存中。从 term index 查到对应的 term dictionary 的 block 位置之后,再去磁盘上找 term,大大减少了磁盘的 random access 次数。
每个节点表示一个ES进程(通常每个节点部署独立机器),每个分片表示一个lucene实例。当节点数发生变化(扩容、缩容)时,会触发分片rebalance。
os cache即文件系统缓存,是属于内存的。segment(包含倒排索引+正排索引)refresh到os cache后就可以被检索,但需要flush到磁盘才持久化。
Translog 的刷盘方式有两种:同步(request)和异步(async)
ES 默认使用的是 request,即每次写入、更新、删除操作后立刻执行 fsync 落盘。
如果使用异步的方式,则根据同步间隔周期性(通常是5s)的刷盘。
数据写入:在主分片节点上,数据会先被写入(index buffer)中,同时写入 translog,这个时候数据还不能被搜索到(这个也是 es 是近实时搜索的原因);
tips:整个过程大部分在内存中,如果断电就会导致数据丢失。因此,ES 引入了 translog,数据写入内存时,会同时写入 translog(会立即落盘),来保证数据不丢失。
4、经过一段时间(默认 1s)或者 index buffer 满了(默认 jvm 的 10%),会将 index buffer 中的文档 refresh 到系统文件缓存(os cache),然后再刷入到 lucene 的底层文件 segment 中,同时建立倒排索引,这个时候文档是可以被搜索到的;
5、 由于 segment 的不可变性,随着 segment 越来越多,每打开一个 segment 就会消耗一个文件句柄,导致查询性能越来越差。这时,ES 后台会有一个单独线程专门合并 segment,将零碎的小的 segment 合并成一个大的 segment;
6、经过一段时间(默认30 min)或者 tanslog 满了(默认512M),会将文件系统缓存的 segment 落盘;
7、如果主分片所在的节点请求执行成功,它会将请求同步转发到副本分片所在节点,做到主副数据的一致性,一旦所有的副本分片都报告成功,主分片节点将向协调节点报告成功,协调节点向客户端报告成功。因此,数据写入,主副本之间采用的是同步写入过程。
正向信息
反向信息(新版本用的是FST,不同于此):
segment的数据结构
Inverted Index
Stored Fields
Document Values
Cache
- Inverted Index
Inverted Index就是我们常见的倒排索引, 主要包括两部分:
一个有序的数据字典 Dictionary(包括单词 Term 和它出现的频率)。
与单词 Term 对应的 Postings(即存在这个单词的文件)
当我们搜索的时候,首先将搜索的内容分解,然后在字典里找到对应 Term,从而查找到与搜索相关的文件内容。
- Stored Field
本质上,Stored Fields 是一个简单的键值对 key-value。默认情况下,Stored Fields是为false的,ElasticSearch 会存储整个文件的 JSON source。
哪些情形下需要显式的指定store属性呢?大多数情况并不是必须的。从_source中获取值是快速而且高效的。如果你的文档长度很长,存储 _source或者从_source中获取field的代价很大,你可以显式的将某些field的store属性设置为yes。缺点如上边所说:假设你存 储了10个field,而如果想获取这10个field的值,则需要多次的io,如果从Stored Field 中获取则只需要一次,而且_source是被压缩过 的。
这个时候你可以指定一些字段store为true,这意味着这个field的数据将会被单独存储(实际上是存两份,source和 Stored Field都存了一份)。这时候,如果你要求返回field1(store:yes),es会分辨出field1已经被存储了,因此不会从_source中加载,而是从field1的存储块中加载。
- Document Values
Doc_values 本质上是一个序列化的 列式存储,这个结构非常适用于聚合(aggregations)、排序(Sorting)、脚本(scripts access to field)等操作。而且,这种存储方式也非常便于压缩,特别是数字类型。这样可以减少磁盘空间并且提高访问速度,ElasticSearch 可以将索引下某一个 Document Value 全部读取到内存中进行操作.
Doc_values是存在磁盘的
在es中text类型字段默认只会建立倒排索引,其它几种类型在建立倒排索引的时候还会建立正排索引,当然es是支持自定义的。在这里这个正排索引其实就是Doc Value。