HyperLoglog算法在Uv实时统计中的应用

1 传统的Uv实时统计方法以及其缺点

给定时间段条件下,实时统计Uv就是统计不重复的访客数。

最简单的方法就是把用户唯一id存储到集合中,每次有新访客,就把向集合新增元素。

但是当数据量千万级别的时候,无论是内存中,还是redis等外部系统中,集合新增元素的效率都很低。

2 HyperLoglog

在不追求绝对准确的情况下,使用概率算法算是一个不错的解决方案。

概率算法不直接存储数据集合本身,通过一定的概率统计方法预估基数值,这种方法可以大大节省内存。

怎么理解HyperLoglog算法呢,

下面是通过mapWithState算子计算单词数的官方示例

...
val stateDstream = wordDstream.mapWithState(
      StateSpec.function(mappingFunc).initialState(initialRDD))

val mappingFunc = (word: String, one: Option[Int], state: State[Int]) => {
    val sum = one.getOrElse(0) + state.getOption.getOrElse(0)
    val output = (word, sum)
    state.update(sum)
    output
}
...

如果这的word代表访客唯一id,那如何统计每天的访客数(DAU)呢?

这里引入Java版本的HLL,来实现大数据背景下的uv实时统计。

maven依赖:

<dependency>
  <groupId>com.clearspring.analytics</groupId>
  <artifactId>stream</artifactId>
  <version>2.9.5</version>
</dependency>

核心逻辑:

import com.clearspring.analytics.stream.cardinality.HyperLogLog;

//rdd类型为RDD[(String,String)], means (dateStr, id)
//设置超时为一天
val stateDstream = visitorDstream.mapWithState(
      StateSpec.function(mappingFuncHLL).timeout(Seconds(86400))
      )

private val mappingFuncHLL = (key: String, one: Option[Set[String]], state: State[HyperLogLog]) => {
    val defaultRes = new HyperLogLog(14)

    if (state.isTimingOut()) {
      (key, defaultRes)
    } else {
      var uv = state.getOption().getOrElse(defaultRes)
      one.foreach(it => {
        it._1.foreach(uv.offer(_))
        state.update(uv)
      })

      (key, uv)
    }
  }

3 性能评估

在Redis里,每个HyperLogLog Key只需占用十几k的内存,就可以估算接近2^64个不同元素的基数。

Redis HyperLogLog测试给出了不同规模数据集下的误差。

uploading-image-616574.png

千万级数据集下,随机数误差基本低于 1.5%, 完全不重复情况下误差也不超过 2%。能满足大部分情况下的需求。

4 讨论

4.1 bitmap

bitmap可以理解为通过一个bit数组来存储特定数据的一种数据结构,每一个bit位都能独立包含信息,bit是数据的最小存储单位,因此能大量节省空间,也可以将整个bit数据一次性load到内存计算。

如果定义一个很大的bit数组,基数统计中每一个元素对应到bit数组的其中一位,例如bit数组1001010代表实际数组[2, 4, 7]

新加入一个元素,只需要将已有的bit数组和新加入的数字做按位或 (or)(or)计算。bitmap中1的数量就是集合的基数值。

bitmap有一个很明显的优势是可以轻松合并多个统计结果,只需要对多个结果求异或就可以。也可以大大减少存储内存,

可以做个简单的计算,如果要统计1亿个数据的基数值,大约需要内存: 100000000/8/1024/1024 \approx≈ 12M

bitmap对于内存的节约量是显而易见的,但是要做到每个元素唯一对应bit数组中固定一位需要一个良好的哈希算法。

我们希望有一个理想的哈希函数hash,能够保证对于元素e, 得到唯一的数字loc = hash(e), loc就是元素e在bit数组中的下标或位置。

怎么得到接近理想的,足够好的哈希函数,这是另一个问题。

4.2 B树

B树最大的优势是插入和查找效率很高,如果用B树存储要统计的数据,可以快速判断新来的数据是否已经存在,并快速将元素插入B树。要计算基数值,只需要计算B树的节点个数。 将B树结构维护到内存中,可以快速统计和计算,

但是B树的问题是只是加快了查找和插入效率,并没有节省存储内存。例如要同时统计几万个链接的UV,每个链接的访问量都很大,如果把这些数据都维护到内存中,实在是够呛。

4.3 HLL的原理

see also [1]

References

  1. 神奇的HyperLogLog算法
  2. HyperLogLog算法详解
  3. Redis HyperLogLog测试
  4. http://blog.codinglabs.org/articles/algorithms-for-cardinality-estimation-part-iv.html

原文地址:https://www.cnblogs.com/lawlietfans/p/10325226.html

时间: 2024-10-16 06:17:41

HyperLoglog算法在Uv实时统计中的应用的相关文章

Flume+Kafka+Storm+Redis构建大数据实时处理系统:实时统计网站PV、UV+展示

[TOC] 1 大数据处理的常用方法 前面在我的另一篇文章中<大数据采集.清洗.处理:使用MapReduce进行离线数据分析完整案例>中已经有提及到,这里依然给出下面的图示: 前面给出的那篇文章是基于MapReduce的离线数据分析案例,其通过对网站产生的用户访问日志进行处理并分析出该网站在某天的PV.UV等数据,对应上面的图示,其走的就是离线处理的数据处理方式,而这里即将要介绍的是另外一条路线的数据处理方式,即基于Storm的在线处理,在下面给出的完整案例中,我们将会完成下面的几项工作: 1

实时统计每天pv,uv的sparkStreaming结合redis结果存入mysql供前端展示

最近有个需求,实时统计pv,uv,结果按照date,hour,pv,uv来展示,按天统计,第二天重新统计,当然了实际还需要按照类型字段分类统计pv,uv,比如按照date,hour,pv,uv,type来展示.这里介绍最基本的pv,uv的展示. id uv pv date hour 1 155599 306053 2018-07-27 18 关于什么是pv,uv,可以参见这篇博客:https://blog.csdn.net/petermsh/article/details/78652246 1.

一步一步写算法(之n!中末尾零的个数统计)

原文:一步一步写算法(之n!中末尾零的个数统计) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 在很多面试的题目中,求n!结果中零的个数也是经常遇到的一道题目.那么这道题目的解决方法究竟是什么呢?我愿意在此和大家分享一下我自己的一些看法,有不同见解的朋友欢迎多提意见. 求n!中零的个数主要在于乘数中有没有能被2和5整除的数,只要能找到被2和5整数的乘数即可,所以,我的代码流程是这样的: (1)查找当前数据中有没有可以整除2的整数,同时修

使用nginx lua实现网站统计中的数据收集

使用nginx lua实现网站统计中的数据收集 导读 网站数据统计分析工具是各网站站长和运营人员经常使用的一种工具,常用的有 谷歌分析.百度统计和腾讯分析等等.所有这些统计分析工具的第一步都是网站访问数据的收集.目前主流的数据收集方式基本都是基于javascript的.在此简要分析数据收集的原理,并按照步骤,带领大家一同搭建一个实际的数据收集系统. 数据收集原理分析 简单来说,网站统计分析工具需要收集到用户浏览目标网站的行为(如打开某网页.点击某按钮.将商品加入购物车等)及行为附加数据(如某下单

网站统计中的数据收集原理及实现

转载自:http://blog.sina.com.cn/s/blog_62b832910102w5mx.html Avinash Kaushik将点击流数据的获取方式分为4种:log files.web beacons.JavaScript tags和packet sniffers,其中包嗅探器(packet sniffers)比较不常见,最传统的获取方式是通过WEB日志文件(log files):而beacons和JavaScript是目前较为流行的方式,Google Analytics目前就

Hbase在数据统计中的应用心得

1. 数据统计的需求 互联网上对于数据的统计,一个重要的应用就是对网站站点数据的统计,例如CNZZ站长统计.百度统计.Google Analytics.量子恒道统计等等. 网站站点统计工具无外乎有以下一些功能: 1)网站流量统计:包括PV.UV.IP等指标,这些统计指标可以以趋势图的形式展示出来,如最近一周.最近一个月等. 2)IP来源信息统计:记录各个来源IP下的访问PV数. 3)访问来源分析:记录访客是从哪些途径到达本网站的. 4)搜索引擎及搜索关键词分析:对于各个指定搜索引擎带来访问PV的

HyperLogLog 算法的原理讲解以及 Redis 是如何应用它的

作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:http://www.cnblogs.com/linguanh/ GitHub : https://github.com/af913337456/ 腾讯云专栏: https://cloud.tencent.com/developer/user/1148436/activities 虫洞区块链专栏:https://www.chongdongshequ.com/

通过Flink实现个推海量消息数据的实时统计

背景 消息报表主要用于统计消息任务的下发情况.比如,单条推送消息下发APP用户总量有多少,成功推送到手机的数量有多少,又有多少APP用户点击了弹窗通知并打开APP等.通过消息报表,我们可以很直观地看到消息推送的流转情况.消息下发到达成功率.用户对消息的点击情况等. 个推在提供消息推送服务时,为了更好地了解每天的推送情况,会从不同的维度进行数据统计,生成消息报表.个推每天下发的消息推送数巨大,可以达到数百亿级别,原本我们采用的离线统计系统已不能满足业务需求.随着业务能力的不断提升,我们选择了Fli

编程算法 - 数字在排序数组中出现的次数 代码(C)

数字在排序数组中出现的次数 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 统计一个数字在排序数组中出现的次数. 通过折半查找, 找到首次出现的位置, 再找到末次出现的位置, 相减即可. 时间复杂度O(logn). 代码: /* * main.cpp * * Created on: 2014.6.12 * Author: Spike */ /*eclipse cdt, gcc 4.8.1*/ #include <stdio.h> #inc