RoaringBitMap是什么?
RoaringBitMap是BitSet的延伸,其在BitSet的基础上对底层结构进行了压缩,减小了内存空间的占用。与未压缩的传统BitSet相比,其性能可能优于其上百倍并且速度会更快。
有什么用?
位图这种数据源结构会用在人物画像方面,某个用户标签下有什么用户,其位上的值则表示在该标签下的用户标识。另外RoaringBitmap支持and、andNot、or、xor集合操作,可以实现不同标签的逻辑操作,比如说女生标签L1、年龄>=25两个标签L2,先要求找出年龄大于25的女生,则可以很方面的操作L1.and(L2)。
怎么用?
基本用法
RoaringBitMap基本用法比较简单
public static void main(String[] args) {
RoaringBitmap rr = RoaringBitmap.bitmapOf(1,2,3,1000); //带初始化操作的实例
RoaringBitmap rr2 = new RoaringBitmap();
rr2.add(4000L,4255L);//范围添加
rr.select(3); // 还回bitmap中index为3的值,这里是1000
rr.rank(2); // 还回2在bitmap中的index,这是1
rr.contains(1000); // 1000在其中
rr.contains(7); // 7不在其中
RoaringBitmap rror = RoaringBitmap.or(rr, rr2);// 逻辑or操作
rr.or(rr2); //逻辑or操作,rr=rr.or(rr2);
boolean equals = rror.equals(rr);// true
if(!equals) throw new RuntimeException("bug");
long cardinality = rr.getLongCardinality();//bitmap中value的个数
System.out.println(cardinality);
序列化
标签记载都是很费时间的,因为要去聚合数据和计算,所以当程序不得不停止时,我们如何把这些数据从内存保存到磁盘,然后程序启动时将这些数据从磁盘加载到内存呢,这里就要用到序列化的知识。
Stream序列化
序列化
//序列化路径
private static String path = "E:\\data\\out.txt";
public static void main(String[] args)throws Exception {
RoaringBitmap rr = RoaringBitmap.bitmapOf(9,3,4,6,7);
rr.add(158);
System.out.println(rr.select(3));
System.out.println(rr.rank(3));
System.out.println(rr.contains(6));
System.out.println(rr.getLongCardinality());
//序列化
FileOutputStream fos = new FileOutputStream(path);
DataOutputStream dos = new DataOutputStream(fos);
rr.serialize(dos);
//数据刷新到磁盘
dos.flush();
dos.close();
}
反序列化
////二进制文件路径
private static String path = "E:\\data\\out.txt";
public static void main(String[] args)throws Exception {
//读取二进制流并包装成ByteBuf
FileInputStream fi = new FileInputStream(path);
DataInputStream di = new DataInputStream(fi);
byte[] bytes = new byte[di.available()];
di.read(bytes,0,di.available());
ByteBuffer bb = ByteBuffer.wrap(bytes);
//ByteBuf还原数据结构
ImmutableRoaringBitmap immutableRoaringBitmap = new ImmutableRoaringBitmap(bb);
RoaringBitmap rr = new RoaringBitmap(immutableRoaringBitmap);
System.out.println(rr.select(3));
System.out.println(rr.rank(3));
System.out.println(rr.contains(6));
}
原理
RoaringBitMap使用的以下位图索引压缩算法:
1.我们将 32-bit 的范围 ([0, n)) 划分为 2^16 个桶,每一个桶有一个 Container 来存放一个数值的低16位;
2.在存储和查询数值的时候,我们将一个数值 k 划分为高 16 位(k % 2^16)和低 16 位(k mod 2^16),取高 16 位找到对应的桶,然后在低 16 位存放在相应的 Container 中;
3.容器的话, RBM 使用两种容器结构: Array Container 和 Bitmap Container。Array Container 存放稀疏的数据,Bitmap Container 存放稠密的数据。即,若一个 Container 里面的 Integer 数量小于 4096,就用 Short 类型的有序数组来存储值。若大于 4096,就用 Bitmap 来存储值。