Bitmap

Bitmap,直译就叫位图。可以理解为通过一个bit数组存储特定数据的一种数据结构;由于bit是数据的最小单位,所以这种数据结构往往是非常节省存储空间的。在Java和Redis中都存在同名实现结构。

在一个记录只有两种状态,是或不是的场景下,如果使用其他数据结构存储则会存在大量空间空间的浪费。即使存在海量的数据,我们也只需要为每个数据分配1byte的空间就可以记录了。比如:用户画像

Bitmap可以节省大量的存储空间,所以可以很容易的倍一次性加载到内存中。Bitmap结构还有一个很重要的特点:可以很方便的进行位运算

比如我们需要统计用户满足以下条件的用户:程序员、带眼镜、长头发。。。。那么我们可以将对相应条件的用户画像的Bitmap结构做AND操作,就可以方便的过滤出满足条件的对象了。

Bitmap的优化

假如一个Bitmap中只有稀疏的那个几个1,那么其他空间是不是就被浪费了呢?

谷歌开发的EWAHComressedBitmap对Bitmap存储空间做了一定的优化操作。

EWAH把Bitmap存储在一个long数组中,long数组的每一个元素都可以当做64位的二进制数,也就是整个Bitmap的子集,称为Word

当创建一个空的Bitmap时,只有4个Word,也就是只有4个long数组,随着数据的不断插入,Word数组会随着进行扩容。

Word节点分为两种,直接存储数据的叫做Literal Word,简称LW。存储跨度信息的叫Running Length Word,简称RLW。

每一个RLW分为两部分,低32位表示当前Word横跨了多少个空Word,高32位表示当前RLW后面又多少个连续的LW。这样即使存在很多个0的位置,也能进行合并,减少浪费。

Bloom Filter

Bitmap适合处理按顺序字段映射,如ID。但是当遇到其他情况时就无能为力了,比如判断一个单词是否存在于单词集中,这个时候如果需要映射的话,只能够对该单词进行相应的hash计算后映射到Bitmap上,But!绝大情况下会存在hash冲突,无法确认是不是。

于是便引入了布隆过滤器。布隆过滤器也不能完全的消除误差。只能说大大的减少了误差率。

布隆过滤器的原理就是将需要判断的对象进行多次不同的hash计算后,同时判断那几位是否都为1,由此可见,布隆过滤器的误差率取决于hash函数的选取。

Cuckoo Filter

布隆过滤器存在一个致命的缺点,那就是已经置为1的位不能再重置为0。这是因为你并不能判断该位具体被多少个对象映射了。只能在你认为误差率已经不能接受时进行重建。