一、倒排索引
参考文章,索引机制如下:
Luncene在对文档建立索引时,给词典的元素排序,在搜索的时候使用二分查找,快速的找到对应的元素;ES期望将词典放在内存,直接从内存读取数据远远快于从磁盘读取数据;
但若将所有的词典加入内存,则会消耗巨量的内存;
二、建立词典加入内存
最终ES索引结构大致如下,其中词典索引(Term Index)在内存中,词典(Term Dictionary)、文档列表(Posting list)在磁盘;
其中Term Index保存在有限状态转换器(Finite State Transducers),相当于是一个前缀树和后缀树结合体;
三、Frame Of Reference (FOR)
3.1 普通的FOR
FST解决的是直接将Term Dictionary放入内存太大的问题,FOR解决的是DOC ID保存在磁盘上太大,查询时加速的问题;
倒排链特性是Doc Id单调递有序排列,可以使用增量编码压。比如:若倒排链上DocID是[73, 300, 302, 332, 343, 372], 增量编码是[73, 227, 2, 30, 11, 29]; 所有的增量都在0~255之间,每一个值都是一个字节存储,原来是两个字节,压缩率50%。 Luncene在磁盘上编码索引技术:倒排链先进行增量编码,然后分块,每块包含256文档,最后位打包压缩每个块,Luncene计算在块中存储增量的最大位数,添加到块头中;
比如:如下图所示,Step 1 计算增量数组,Step 2 按每3个数字分块,Step 3计算每块中存储最大数字所需要的比特数,并添加到块头。如 [73,227,2] 最大数是 227 需要 8 bits,总共需要8*3=24 bits=3 bytes。
3.2 Patched Frame Of Reference (PFOR)
普通的FOR如果遇到明显离群点,压缩性能急剧下滑,比如:[1,2,293,3,4,5], 293需要使用9bits来编码,其他的只需要3bits编码,极大降低压缩效率;PFOR将大多数(90%)选择规定位数来保存b(b指存储最大值所需最大位数),不能用b位保存的异常数组分配到异常数组中保存;
举例:增量数组[1,2,293,3,4,5,301],其中有两个异常值 '293' 和 '301'。设定b=3,那么在293这个位置上,存储和异常值301的位置距离4.而301是最后一个异常值,其值是0.
四、Roaring BitMaps
Elastic Search针对每一个词条查询的结果,都可以完美的保存在一个BitMap中,但是普通BitMap可能存在空间效率问题,进而ES改用Roaring BitMap保存查询的结果;(参考Roaring BitMap介绍), ES通过缓存(Filter,segment) -> BitMap的映射来加快查询;