RoaringBitmap简析

更新一: RoaringBitmap源码分析一(AND操作)

Bitmap索引在数据库和搜索引擎里使用的很广泛。最近发现几个实时OLAP分析引擎,比如Druid和Pinot也都在用,所以深入研究了一下。这两个OLAP引擎都使用RoaringBitmap,这是一种压缩的、高效的bitmap索引。代码很精妙,看得很过瘾。

Bitmap索引一般用来存储整数。整数的范围是0~2^32-1。所以如果用最朴素的思想,一个bit位代表一个整数是否存在,可以计算出所占用的大小就是2^32/8/1024/1024 = 512M。而且再考虑到大多数情况下,bitmap中元素不会太多,反而是非常的稀疏,用512M的空间来存储一个稀疏的bitmap,自然是不可接受的。

在RoaringBitmap中,32位整数被分成了2^16个块。任何一个32位整数的前16位决定放在哪个块里。后16位就是放在这个块里的内容。比如0xFFFF0000和0xFFFF0001,前16位都是FFFF,表明这两个数应该放在一个块里。后16位分别是0和1。在这个块中指保存0和1就可以了,不需要保存完整的整数。

在最开始的时候,一个块中包含一个长度为4的short数组,后16位所对应的值就存在这个short数组里。注意在插入的时候要保持顺序性,这里就需要用到二分查找来加快速度了。如果当块中的元素大于short数组的长度时,就需要重新分配更大的数组,把当前数组copy过去,并把新值插入对应的位置。扩展数组大小和STL中vector的方式类似,不过并不是完全的加倍,而且上限是4096,也就是说最多只保存4096个元素。那么问题来了,超过了4096怎么办呢?

一个块里最多可能需要存放2^16个元素,那么如果是用short来存放,最多需要65536个short,那么就是131072个byte。如果换一种方式,用位来存储元素,那么就需要65536个bit,相当于1024个long型数组,即2048个int,也就是4096个short。

所以,当一个块中元素数量小于等于4096的时候,用有序short数组来保存元素,而当元素数量大于4096的时候,用长度为1024的long数组来按位表示元素是否存在。

当bitmap中有多个块的时候,块的信息是用数组来保存的。这个数组同样需要保持顺序性,也是用二分查找找到一个块的位置。所以,当一个整数过来之后,首先根据前16位计算出块的key,然后在块的数组中二分查找。找到的话,就把后16位保存在这个块中。找不到,就创建一个新块,把后16位保存在块中,再把块插入对应的位置。

下面这张图可以清楚的看到roaringbitmap中是如何用两种形式来保存数据的。图片来自RoaringBitmap的论文,内容很丰富,还包含很多性能测试。

除了上述这些内容之外,RoaringBitmap还有相当多的代码用来实现快速高效的位图运算,比如AND,OR,XOR等。这里面的代码也同样非常精巧,值得深入研究,下次再分析吧。

你可能感兴趣的:(RoaringBitmap简析)