美文网首页Flink
Flink+HyperLogLog实现海量实时去重计数

Flink+HyperLogLog实现海量实时去重计数

作者: LittleMagic | 来源:发表于2020-05-06 22:59 被阅读0次

今天忙到飞起(到现在还没完),写一篇超短的小技巧吧。

HyperLogLog是去重计数的利器,能够以很小的精确度误差作为trade-off大幅减少内存空间占用,在不要求100%准确的计数场景极为常用。关于它的数学原理,看官可参见之前写过的《再谈基数估计之HyperLogLog算法》,不再赘述了。

在用Flink做实时计算的过程中,也短不了做去重计数,比如统计UV。我们当然可以直接借助Redis的HyperLogLog实现,但是要在Flink job内直接整合HyperLogLog该怎么做呢?

先引入如下Maven依赖项:

<dependency>
  <groupId>net.agkn</groupId>
  <artifactId>hll</artifactId>
  <version>1.6.0</version>
  <scope>compile</scope>
</dependency>

下面的聚合函数即可实现从WindowedStream按天、分键统计PV和UV。

WindowedStream<AnalyticsAccessLogRecord, Tuple, TimeWindow> windowedStream = watermarkedStream
  .keyBy("siteId")
  .window(TumblingEventTimeWindows.of(Time.days(1)))
  .trigger(ContinuousEventTimeTrigger.of(Time.seconds(10)));

windowedStream.aggregate(new AggregateFunction<AnalyticsAccessLogRecord, Tuple2<Long, HLL>, Tuple2<Long, Long>>() {
  private static final long serialVersionUID = 1L;

  @Override
  public Tuple2<Long, HLL> createAccumulator() {
    return new Tuple2<>(0L, new HLL(14, 6));
  }

  @Override
  public Tuple2<Long, HLL> add(AnalyticsAccessLogRecord record, Tuple2<Long, HLL> acc) {
    acc.f0++;
    acc.f1.addRaw(record.getUserId());
    return acc;
  }

  @Override
  public Tuple2<Long, Long> getResult(Tuple2<Long, HLL> acc) {
    return new Tuple2<>(acc.f0, acc.f1.cardinality());
  }

  @Override
  public Tuple2<Long, HLL> merge(Tuple2<Long, HLL> acc1, Tuple2<Long, HLL> acc2) {
    acc1.f0 += acc2.f0;
    acc1.f1.union(acc2.f1);
    return acc1;
  }
});

上述开源HyperLogLog组件的主要方法简述如下:

  • HLL(int log2m, int regwidth)
    创建一个HyperLogLog对象。log2m即总分桶数目以2为底的对数,regwidth则是真正用来做基数估计的比特的下标值宽度。根据Redis的思路,log2m=14,regwidth=6,即可以仅用最多12kB内存,以0.81%的误差计算接近264的基数。

  • void addRaw(long rawValue)
    向HyperLogLog中插入元素。如果插入的元素非数值型的,则需要hash过后(推荐用Murmur3等比较快的哈希算法)再插入。

  • long cardinality()
    返回该HyperLogLog中元素的基数。

  • void union(HLL other)
    将两个HyperLogLog结构合并为一个。

该HyperLogLog组件如同Redis一样实现了稀疏存储与密集存储两种方式,以进一步减少内存占用量。其源码不难理解,看官可以自行参看。

最后,如果一定追求100%准确,该怎么办呢?普通的位图法显然不合适,应该采用压缩位图,如笔者之前提到过的RoaringBitmap

继续忙去了。民那好梦。

相关文章

  • Flink+HyperLogLog实现海量实时去重计数

    今天忙到飞起(到现在还没完),写一篇超短的小技巧吧。 HyperLogLog是去重计数的利器,能够以很小的精确度误...

  • 数据库 | MySQL | 5. 数据操作(复杂查询)

    查询排序 顺序 倒序 去重 单字段去重 分组去重 计数 计数(不含null) 去重计数(不含null) 分组计数(...

  • 海量数据去重

    一个文件中有40亿条数据,每条数据是一个32位的数字串,设计算法对其去重,相同的数字串仅保留一个,内存限制1G. ...

  • 架构学习--推拉消息学习

    具体案例学习: 1.系统对单个用户通知 比如微博实现好友计数: 实现不刷新网页,计数实时变化的需求。 如果使用推送...

  • 元素去重、计数

  • 海量数据去重-精确去重[Bitmap]

    假如我们使用Bitmap(或称BitSet)储存,定义一个很大的bitmap数组,每个元素对应Bitmap中的1位...

  • simHash海量文本去重

    simHash是google提出的用于计算海量文本相似度的算法:(1) 分词 => word(2) 单词权重 tf...

  • 海量文档的去重

    思路: 文本的向量化表示1.1 simhash在线去重 抽屉原理1.2 word2vec1.3 bagofword...

  • 关于双11的故事手机直播

    手机直播互动点赞 PV:就是计数器加一操作另外如果在加上两个业务场景那?1) 高并发,海量请求,至少千万2) 实时...

  • Redis面试题

    五种应用结构及它们的应用场景 String:计数器:许多系统都会使用Redis作为系统的实时计数器,可以快速实现计...

网友评论

    本文标题:Flink+HyperLogLog实现海量实时去重计数

    本文链接:https://www.haomeiwen.com/subject/omogghtx.html