HyperLogLog:海量数据下的基数计算

1. 什么是基数计算

基数计算(cardinality counting)指的是统计一批数据中的不重复元素的个数,常见于计算独立用户数(UV)、维度的独立取值数等等。实现基数统计最直接的方法,就是采用集合(Set)这种数据结构,当一个元素从未出现过时,便在集合中增加一个元素;如果出现过,那么集合仍保持不变。
在大数据的场景中,实现基数统计往往去面临以下的两个问题:

  • 如果有效的存储原始数据,以避免数据占用空间过多,这里就涉及到存储空间压缩的问题
  • 如果能够跨不同的维度、不同的时间段实现基数计算,比如在计算日度UV的情况下,如果计算出周度、或者月度的UV

本文旨在介绍目前比较成熟的基数计算的方式,并通过实例对比他们在解决以上两个问题上的效果,最后引出本文的重点,HyperLogLog算法的实现和应用。

2. Bitmap

2.1 基本原理

Bitmap进行基数计算的方法,是先定义一个bit数组,数组中的每一位对应数据的一种取值。由于bit是计算机中的最小单位,使用bit可以大量的减少存储空间。例如一个数组[1,3,4,5],那么对应的bitmap即为[0,0,0,1,1,1,0,1],后续每新增加一个元素,就和现有的bitmap进行OR操作,通过计算bitmap中1的个数,即可以得到基数计算的结果。


正是因为bitmap之间对OR也是良好支持的,两个bitmap在进行OR操作之后,便是这两个条件组合下的基数计算结果,因此使用bitmap是可以实现任意条件下的基数计算。

2.2 空间使用

按照上面介绍的原理,进行bitmap的构建。假如统计1亿数据的基数值,大约需要内存100000000/8/1024/1024 ~= 12M,如果有100个这样的对象,就需要1.2G的内存空间,可见占用内存还是很大的,在实际业务中基本很少使用。

3. Linear Counting

3.1 基本原理

Linear Counting是采用概率的方式进行基数估计的最简单的方法。下面通过一个实例描述Linear Counting的计算过程:

  • 数据哈希:假设原始数据的基数为n,使用一组哈希空间为m的哈希函数H,将原始数据转换为满足均匀分组的一组哈希数组。
  • 分桶数据统计:构建一个长度为m的bitmap,其中每一个bit对应哈希空间的一个值。生成哈希数组的值如果存在,则把相应的bit设置为1。当所有值设置完成后,统计bitmap中为0的bit数为u。


可以通过下述的公式计算基数估计的结果:



注意这里的log指的是自然对数。

公式的推导过程有兴趣的可以参考这篇文章。其中最重要的是要清楚,在经过n次数据的哈希后,bitmap中的某个bit值为0,是一个伯努利事件。记住这一点再理解公式推导就容易多了。

3.2 空间使用

Linear Counting的空间使用,和bitmap相比,空间复杂度是一致的,仅有线性下降。因此如果对于1亿的原始数据,仍然需要MB级别的内存空间存储。Linear Counting在实际应用中也很少被使用。

4. LogLog Counting

4.1 伯努利过程

在介绍LogLog Counting之前,我们先来回顾一下伯努利过程的概念。

伯努利过程是一个由有限个或无限个的独立随机变量 X1, X2, X3 ,..., 所组成的离散时间随机过程,其中 X1, X2, X3 ,..., 满足如下条件:
对每个 i, Xi 等于 0 或 1; 对每个 i, Xi = 1 的概率等于 p. 换言之,伯努利过程是一列独立同分布的伯努利试验。每个Xi 的2个结果也被称为“成功”或“失败”。所以当用数字 0 或 1 来表示的时候,这个数字被称为第i个试验的成功次数。

举一个常见的例子:每次抛硬币之后,出现正面和反面的概率分别为1/2,如果不停地抛硬币,直至出现正面为止,这就是一个伯努利过程。
这样,我们假设一共进行了n次伯努利过程,出现正面的次数分别为k1, k2, ... kmax,那么有以下两个结论:

  • n次伯努利过程的投掷次数都不大于kmax
  • n次伯努利过程,至少有一次的投掷次数等于kmax

已知投掷k次才出现正面的概率为:1/2^k,那么:

  • 第一种情况的概率为:


  • 第二种情况的概率为:


如果n >> 2^k,则P(x >= kmax)为0;如果n << 2^k,则P(x <= kmax)为0。因此我们可以用2^k来作为n的近似估计结果。

4.2 伯努利过程与LogLog Counting

如何将基数计算,等价地认为是一个伯努利过程,是LogLog Counting的关键所在。这里我们可以把原始数据进行哈希,哈希后的数组是满足均匀分布的。把每个元素看做一个投掷硬币的过程,将元素转换为2进制之后,每个bit出现0和1的概率是相等的。从高位开始查,第一次出现1的位置记为k,即等同于投掷硬币时出现第一个正面,将所有元素出现1的位置的最大值,记为kmax,那么2^kmax就是基数计算的结果。

4.3 LogLog Counting计算过程
  • 数据哈希:这个和Linear Counting是类似的,都需要保证哈希后的数据是满足均匀分布的。
  • 转换为2进制:将哈希后的每个元素,都转换为2进制,由于数据在哈希后满足均匀分布的,2进制数据每一个bit的0和1出现的概率都是1/2,这里设2进制数据的位数为L。
  • 统计第一个1出现的位置:分别计算每个2进制数据,第一次出现1的次数。所有次数中的最大值为kmax,那么2^kmax就是最终结果。

下图中给出一个针对一个元素进行k值计算的过程。


4.4 数据分桶

上面的计算过程,由于是单一估计量,可能会出现一定的偶然性导致误差。因此这里引入数据分桶的方法。取哈希空间分成m个桶,用哈希值的前几个bit的值来决定数据属于哪一个桶,再对桶内的数据取k值,最终计算出kmax。再将所有桶的kmax取平均数,这样就通过多次估计取平均的方式,消除了单一估计可能存在的偶然性误差。计算公式如下:


4.5 误差修正和分析

以上的过程仍然是存在误差的,并不是无偏估计。将上述过程修正为无偏估计的过程由于过于复杂,这里就不再介绍了。需要了解的是,最终结果的误差公式为:


4.6 空间使用

到这里,我们就可以理解LogLog Counting中两个log了,它们的含义分别如下:

  • 第一次log,和Linear Counting很类似,由于使用哈希,压缩了数据空间。
  • 第二次log,由于在存储哈希值的第一次1出现的次数时,只需要存储结果k,而不需要存储原始的哈希值,进一步节省了空间。

加入哈希之后的值有32bit,那么每个桶需要5bit保存kmax的值,m个桶就是m5/8 B。
如果基数是1亿个(227),当分桶数为1024时,每个桶的基数上限为227 / 2^10 = 217,log(log(217))=4.09,那么每个桶需要5bit保存kmax,总共需要的空间为5
1024/8,等于640B,可见是非常小的。

5. Adapative Counting

通过概率计算可知,LogLog Counting由于使用了几何平均值,可能出现在基数较小的情况,有些桶是为空的。空桶对于最后平均值的计算干扰较大。
Adapative Counting的思想是将Linear Counting和LogLog Counting进行结合。Linear Counting和LogLog Counting的存储结构是类似的,仅仅是Linear Couting关心桶是否为空,而LogLog Counting需要桶中的kmax。

最终分析得到的结论是:在空桶率大于0.051时,使用Linear Counting的偏差率更小;在空桶率小于0.051时,使用LogLog Counting的偏差率更小。

6. HyperLogLog Counting

HyperLogLog Counting,是在LogLog Counting的基础上,将桶之间计算采用的几何平均,修改为调和平均,可以有效的减少空桶对于平均值的影响。
调和平均的计算公式如下:


使用调和平均后的偏差公式为:



可见偏差期望和LogLog Counting相比要更小。

参考文献

  1. Sketch of the Day: HyperLogLog — Cornerstone of a Big Data Infrastructure
  2. 解读Cardinality Estimation算法(第一部分:基本概念)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,458评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,030评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,879评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,278评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,296评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,019评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,633评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,541评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,068评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,181评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,318评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,991评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,670评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,183评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,302评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,655评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,327评论 2 358

推荐阅读更多精彩内容

  • 姓名:周黎明 组别:宁波盛和塾第 224期努力一组 日精打卡时间:精打卡第213天 知~学习 1、 背诵《六项精进...
    A周黎明阅读 239评论 0 0
  • 小毛猴/文 坐在摇摇晃晃的列车上,跟着列车慢慢走向归家的方向,这次回家让我有了不一样的感觉,经过这一年炼狱般的历练...
    小毛猴阅读 239评论 0 0
  • SaberTwilight的测试文章
    SaberTwilight阅读 143评论 0 0
  • 本来觉呢你超级无敌好,可是每天守在手机旁等你一两句回话,一天,一周,半个月过去了,我真的好累
    23c5c7d41d51阅读 173评论 0 0