flink:RoaringBitmap在亿级用户实时UV精确去重中应用
Posted 菠萝科技
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了flink:RoaringBitmap在亿级用户实时UV精确去重中应用相关的知识,希望对你有一定的参考价值。
未完
目录
1 RoaringBitmap 概念
位集,也称为位图,通常用作快速数据结构。不幸的是,它们可能会使用太多内存。为了弥补这个缺点,我们经常使用压缩位图。
RoaringBitmap 是压缩位图,其性能往往优于传统的压缩位图,例如 WAH、EWAH 或 Concise。某些情况下可以快数百倍,甚至可以比未压缩的位图更快。他被广泛应用于许多家大型系统,如Apache Spark,Apache Hive,Apache Tez,Apache Kylin,Apache CarbonData,Netflix Atlas,OpenSearchServer,zenvisage,Jive Miru,Tablesaw,Apache Hivemall,Gaffer,Apache Pinot and Apache Druid--https://github.com/RoaringBitmap/RoaringBitmap
RoaringBitmap 常用于去重、标签筛选、时间序列等计算中。
( 菠萝科技备注:Apache Kylin RoaringBitmap 技术分享链接 xxx后面补充xx
2021.7.7日更:
大数据分析常用去重算法分析『Bitmap 篇』 - Kyligence的文章 - 知乎
https://zhuanlan.zhihu.com/p/65109143
【视频 + PPT】如何使用 Kylin 进行海量自定义标签的用户画像分析? - Kyligence的文章 - 知乎
https://zhuanlan.zhihu.com/p/100131550
)
2 位图的比较
2.1 与bbc、 WAH、EWAH 或 Concise 比较
#Oracle 的 BBC(字节对齐位图代码)在这一点上是一种过时的格式:虽然它可能提供良好的压缩,但由于过度分支,它可能比最近的替代方案慢得多。
#WAH(字对齐混合)是 BBC 的专利变体,可提供更好的性能。
#Concise 是获得专利的 WAH 的变体。在某些特定情况下,它可以比 WAH 压缩得更好(最多好 2 倍),但通常更慢。
#EWAH(Enhanced Word Aligned Hybrid)都是免费的,而且比上面所有的都要快。不利的一面是,它也不会压缩。它更快,因为它允许某种形式的“跳过”未压缩的单词。因此,尽管这些格式在随机访问方面都不是很好,但 EWAH 比替代方案更好。
然而,这些格式存在一个大问题,在某些情况下可能会严重伤害您:没有随机访问。如果要检查集合中是否存在给定值,则必须从头开始并“解压缩”整个内容。这意味着如果你想将一个大集合与一个大集合相交,在最坏的情况下你仍然需要解压缩整个大集合。
RoaringBitmap解决了这个问题。它以下列方式工作。它将数据分成 2 16 个整数的块(例如, [0, 2 16),[2 16 , 2 x 2 16),...)。在块中,它可以使用未压缩的位图、简单的整数列表或运行列表。无论它使用什么格式,它们都允许您快速检查任何一个值的存在(例如,使用二进制搜索)。最终结果是 Roaring 可以比 WAH、EWAH、Concise 等游程编码格式更快地计算许多操作......也许令人惊讶的是,Roaring 通常还提供更好的压缩率。--https://github.com/RoaringBitmap/RoaringBitmap
更多原理待补充xxxx
2.2 与Bloom Filter和HyperLogLog比较
只可以插入元素,不能删除元素;
不保证100%准确,总是存在误差。
更多比较待补充
3 科学文献
- Daniel Lemire、Owen Kaser、Nathan Kurz、Luca Deri、Chris O'Hara、François Saint-Jacques、Gregory Ssi-Yan-Kai,Roaring Bitmaps:优化软件库的实现,软件:实践与经验 48 (4), 2018 arXiv:1709.07821
- Samy Chambi、Daniel Lemire、Owen Kaser、Robert Godin,使用 Roaring 位图实现更好的位图性能,软件:实践和经验第 46 卷,第 5 期,第 709-719 页,2016 年 5 月http://arxiv.org/abs/1402.6407本文使用的数据来自http://lemire.me/data/realroaring2014.html
- Daniel Lemire、Gregory Ssi-Yan-Kai、Owen Kaser,通过 Roaring 始终如一地更快更小压缩位图,软件:实践和经验 46 (11),2016 年。http://arxiv.org/abs/1603.06549
- 萨米Chambi,丹尼尔·雷赛,罗伯特·戈丁卡迈勒Boukhalfa,查尔斯·艾伦,方进杨,优化德鲁伊咆哮的位图,IDEAS 2016年,2016年http://r-libre.teluq.ca/950/
4 API 文档
http://www.javadoc.io/doc/org.roaringbitmap/RoaringBitmap/
5 java示例
引入jar
//版本及对应
Version 0.7.x requires JDK 8 or better
Version 0.6.x requires JDK 7 or better
Version 0.5.x requires JDK 6 or better
To build the project you need maven (version 3).
//maven依赖
<dependencies>
<dependency>
<groupId>org.roaringbitmap</groupId>
<artifactId>RoaringBitmap</artifactId>
<version>0.9.9</version>
</dependency>
</dependencies>
//Code sample
import org.roaringbitmap.RoaringBitmap;
public class Basic
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); // would return the third value or 1000
rr.rank(2); // would return the rank of 2, which is index 1
rr.contains(1000); // will return true
rr.contains(7); // will return false
RoaringBitmap rror = RoaringBitmap.or(rr, rr2);// new bitmap
rr.or(rr2); //in-place computation
boolean equals = rror.equals(rr);// true
if(!equals) throw new RuntimeException("bug");
// number of values stored?
long cardinality = rr.getLongCardinality();
System.out.println(cardinality);
// a "forEach" is faster than this loop, but a loop is possible:
for(int i : rr)
System.out.println(i);
尽管 Roaring Bitmaps 是为 32 位情况设计的,但有对 64 位整数的扩展。为此,我们提供了两个类:Roaring64NavigableMap和Roaring64Bitmap.
在 Roaring64NavigableMap
依靠传统的红黑树。键是表示元素的最高有效 32 位的 32 位整数,而树的值是 32 位 Roaring 位图。32 位 Roaring 位图表示一组元素的最低有效位。
较新的Roaring64Bitmap
方法依赖于 ART 数据结构来保存键/值对。密钥由最重要的 48 位元素组成,而值是 16 位 Roaring 容器。它的灵感来自Leis等人的 The Adaptive Radix Tree: ARTful Indexing for Main-Memory Databases。(ICDE '13)。
import org.roaringbitmap.longlong.*;
// first Roaring64NavigableMap
LongBitmapDataProvider r = Roaring64NavigableMap.bitmapOf(1,2,100,1000);
r.addLong(1234);
System.out.println(r.contains(1)); // true
System.out.println(r.contains(3)); // false
LongIterator i = r.getLongIterator();
while(i.hasNext()) System.out.println(i.next());
// second Roaring64Bitmap
bitmap1 = new Roaring64Bitmap();
bitmap2 = new Roaring64Bitmap();
int k = 1 << 16;
long i = Long.MAX_VALUE / 2;
long base = i;
for (; i < base + 10000; ++i)
bitmap1.add(i * k);
bitmap2.add(i * k);
b1.and(bitmap2);
6 使用内存映射位图
如果你想让你的位图位于内存映射文件中,你可以使用 org.roaringbitmap.buffer 包。它包含两个重要的类,ImmutableRoaringBitmap 和 MutableRoaringBitmap。MutableRoaringBitmaps 派生自 ImmutableRoaringBitmap,因此您可以在恒定时间内将 MutableRoaringBitmap 转换(转换)为 ImmutableRoaringBitmap。
一个不是 MutableRoaringBitmap 实例的 ImmutableRoaringBitmap 由一个 ByteBuffer 支持,它会带来一些性能开销,但增加了数据可以驻留在任何地方(包括 Java 堆之外)的灵活性。
有时您可能需要使用驻留在磁盘上的位图(ImmutableRoaringBitmap 的实例)和驻留在 Java 内存中的位图。如果您知道位图将驻留在 Java 内存中,那么最好使用 MutableRoaringBitmap 实例,不仅可以修改它们,而且速度也会更快。此外,由于 MutableRoaringBitmap 实例也是 ImmutableRoaringBitmap 实例,因此您可以编写大部分代码,期望使用 ImmutableRoaringBitmap。
如果您编写代码期望 ImmutableRoaringBitmap 实例,而不尝试强制转换实例,那么您的对象将是真正不可变的。MutableRoaringBitmap 有一个方便的方法 (toImmutableRoaringBitmap),它是一个简单的转换回 ImmutableRoaringBitmap 实例。从语言设计的角度来看,ImmutableRoaringBitmap 类的实例只有在按照 ImmutableRoaringBitmap 类的接口使用时才是不可变的。鉴于该类不是 final,可以通过其他接口修改实例。因此,我们不会以纯粹的方式来使用“不可变”一词,而是以一种实际的方式来使用。
我们设计这种 MutableRoaringBitmap 实例可以转换为 ImmutableRoaringBitmap 实例的动机之一是位图通常很大,或者用于避免内存分配的上下文中,因此我们避免强制复制。如果需要混合和匹配 ImmutableRoaringBitmap 和 MutableRoaringBitmap 实例,则可以预期副本。
以下代码示例说明了如何从 ByteBuffer 创建 ImmutableRoaringBitmap。在这种情况下,构造函数只将元数据加载到 RAM 中,而实际数据是根据需要从 ByteBuffer 访问的。
import org.roaringbitmap.buffer.*;
//...
MutableRoaringBitmap rr1 = MutableRoaringBitmap.bitmapOf(1, 2, 3, 1000);
MutableRoaringBitmap rr2 = MutableRoaringBitmap.bitmapOf( 2, 3, 1010);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
// If there were runs of consecutive values, you could
// call rr1.runOptimize(); or rr2.runOptimize(); to improve compression
rr1.serialize(dos);
rr2.serialize(dos);
dos.close();
ByteBuffer bb = ByteBuffer.wrap(bos.toByteArray());
ImmutableRoaringBitmap rrback1 = new ImmutableRoaringBitmap(bb);
bb.position(bb.position() + rrback1.serializedSizeInBytes());
ImmutableRoaringBitmap rrback2 = new ImmutableRoaringBitmap(bb);
或者,我们可以ByteBuffer使用该serialize(ByteBuffer)方法直接序列化为 a 。
对 ImmutableRoaringBitmap 的操作,例如和、或、异或、翻转,将生成位于 RAM 中的 RoaringBitmap。顾名思义,ImmutableRoaringBitmap 本身无法修改。
这个设计的灵感来自德鲁伊。
可以在测试文件 TestMemoryMapping.java 中找到一个完整的工作示例。
请注意,您不应将 org.roaringbitmap 包中的类与 org.roaringbitmap.buffer 包中的类混合在一起。它们不相容。然而,它们序列化为相同的输出。org.roaringbitmap 包中的代码的性能通常是优越的,因为没有由于使用 ByteBuffer 实例而造成的开销。
7 roaringbitmap案例
1 Flink+Hologres亿级用户实时UV精确去重最佳实践 https://zhuanlan.zhihu.com/p/376130674
2 苏宁6亿会员是如何做到快速精确分析的 https://blog.51cto.com/u_14410880/2545887
本文参考官方文档:
https://github.com/RoaringBitmap/RoaringBitmap
以上是关于flink:RoaringBitmap在亿级用户实时UV精确去重中应用的主要内容,如果未能解决你的问题,请参考以下文章