正排索引和倒排索引

883 阅读5分钟

介绍

正排索引、倒排索引是搜索数据库中常见的两种索引结构。一般关系型数据库中采用正排索引,而一些文档数据库中采用倒排索引。

正排索引

  • 正排索引是一种基于文档的索引结构,它将文档按照其出现的顺序进行索引,每个文档对应一个文档号,文档中的每个词条都会记录在索引中。
  • 在正排索引中,可以根据文档号快速定位到对应的文档,然后再进行检索和分析。

倒排索引

  • 倒排索引是一种基于词条的索引结构,它将每个词条对应的文档号列表进行索引,也就是说,对于每个词条,记录了包含该词条的文档号。
  • 在倒排索引中,可以根据某个词条快速定位到包含该词条的文档列表,然后再检索和分析这些文档。

对比

  • 正排索引是基于文档的索引结构,而倒排索引是基于词条的索引结构。
  • 正排索引可以快速定位到文档,倒排索引可以快速定位到包含某个词条的文档列表。
  • 正排索引适合于文档级别的操作,倒排索引适合于词条级别的操作。

倒排索引原理

数据结构

  • 倒排索引的主要数据结构是一个包含了词条(term)和对应文档列表的数据结构。这个结构通常以哈希表(hash table)的形式存储,其中词条作为键(key),对应的文档列表则是值(value)。这样可以快速地根据词条查找到相应的文档列表。
  • 对于每个词条,文档列表可以使用数组、链表、树等数据结构进行存储。常见的做法是使用压缩的数据结构来存储文档列表,以节省内存和提高检索性能。
  • 为了支持快速的词项关联,通常会使用词项词典(terms dictionary)来存储词条及其对应的位置,以便在进行检索时能够快速定位到词条的位置。

示例

有以下文档:

Document 1: Hello world, this is a document.
Document 2: Hello, my name is zm

elasticSearch会将上述文档存储为:

词条(term dictionary)posting list
hello1,2
world1
this1
is1,2
a1
document1
my2
name2
zm2

以上为简单的结构描述,当有数亿条数据,那么一个高频term对应的posting list可能就是数百万的,假设文档编号是int类型,1 int = 4byte,那么一百万就要4MB;而elasticSearch在各个方面都对该数据结构进行了优化。

压缩算法

当词条大面积重复时,postion list是巨大的,此时有两种压缩算法。

  1. frame Of reference(for):

假设目前posting list存储了文档编号为:200,300,302,350,380,403。

image.png

一共7个int类型文档编号,占用空间为7*4=28byte;for压缩算法,会对把上述更改为递增数组。变化后数组为:

image.png

而一个int类型占4byte(32bit)存储的最大数字为2147483648;此时for会压缩每个数字占用的bit。上图中最大数字为192需要9bit,最小数字2需要占用2bit,所有数字都采用9bit,一共需要7*9=63bit(8byte),同时还需要增加1bit用来记录是采用几bit进行压缩的,一共占用9byte,缩小不到原来的三分之一。但都采用同样的bit位进行压缩,当数组中有一个特别大的数字时压缩效果就打打折扣了,所以for还进一步了优化。如图:

image.png

上图中如果只采用一种bit进行压缩的话,那么最终的数据大小为 1byte + 8 * 10bit = 11byte;而采用分割数组使用2种bit进行压缩最终数据大小为 1byte + 2 * 10bit + 1byte + 6 * 6bit = 10byte (当占用不足1byte时需要进位)。

  1. Roaring Bitmaps(rbp):

当数据过于稀疏时,采用for压缩算法带来的压缩效果就微乎其微了。例如: 91,66000,140000,142000,280000;此时会根据65536进行取模计算,此时数据变为:

image.png

image.png

存储结构如上图;而目前container是采用的array container,由于是对65536取模,所以每一个数占16为,内存占用是线性增加的;当数据过多时会转换为bitmap container,它是一个65536个bit组成的map,总大小为8kb;相当于array container存储了4096个数。而当数据是连续的时候例如1-100w,它会直接使用runcontainer,存储结果是[1-100w],只需要8byte,压缩到了极致。

FST构建过程

词项字典(term dictionary)和词项索引采用的fst压缩算法;fst的结构如下:

image.png

对开头和结尾都有进行复用;es具体构建fst是一个很复杂的过程,后续在写一篇文章补充。上图网址:examples.mikemccandless.com/fst.py?term…

提问

以上压缩算法默认document id为int类型,如果是其他类型如何处理? document id采用自增,消耗殆尽了es如何处理?


原创:转载请附链接