HyperLogLog学习总结

文章目录

    • 引言
    • HLL的内部结构
      • 为什么每个桶是6bit?
    • 存储方式
      • 稀疏存储
      • 密集存储

引言

每次扔硬币的结果记录到对应indexbit上,反面为0,正面为1,则最低位的1所在的index为maxIndex,此时可推出,需要扔出正面的次数,为2^maxIndex次。HLL就是类比此思想,在大量数据的情况下,统计低位首个1的位置来记录基数。

HLL的内部结构

HLL中包含很多个桶,每个数值在统计前会先hash,然后根据hash的低14位找到合适的桶号,再根据hash前50位找到第一个低位1的位置,用于比较该桶的基数(即桶的6bit整数值),两者取大值,最终只要将所有桶的基数值进行调和平均就能得到较为准确的基数值了。

为什么每个桶是6bit?

因为14位bit作为桶的下标,故而有2的14次方即16384个桶。再从剩下来的50位中找到首个低位1出现的index至多为50,也就是不超过2^6(即64),所以用6bit就能标识出首次出现1的位置,这就是每个桶为6bit大小了。

存储方式

HLL不是一开始就直接分配12kb大小。一开始HLL是稀疏存储,故而先分配了2B作为其大小,就是下文的稀疏存储的01xxxxxx yyyyyyyy结构。之后根据变化,可以变为密集存储。

稀疏存储

在数据量比较少的时候,HLL使用了稀疏存储。这种 结构会有许多个小结构组成。
小结构包括:

  • 00xxxxxx:(ZERO) 前两个0表示 连续m个桶基数都为0,后6位的整数值加1表示m,我们可以得知该结构最多表示2^6-1+1(即64)个连续为0的桶。所以会有01xxxxxx yyyyyyyy这种结构。
  • 01xxxxxx xxxxxxxx:(XZERO) 前两位01表示 连续为0且超过64个桶的情况。后14位足以表示连续2^14-1+1(即16384)个桶的基数均为0的情况。
  • 1yyyyyxx: (VAL) 第一个1表示 连续m个桶基数都为n。xx的整数值加1即为m,yyyyy的整数值加1即为n。我们可以得知此时n最大为2^5-1+1(即32).。当某个这种结构的n超过32时,整个hll会不可逆转的变成密集存储。

密集存储

密集存储就是连续的16384个桶排放在一起,每个桶就是一个6bit的位图。最终计算基数,就是统计所有桶的基数。由于每个桶只有6bit,所以会出现跨字节存储的情况。如果桶的下标记为index,那么桶的偏移量就是index6/8 个字节,在桶字节中的位置就是index6%8位。
比如,第二个桶的基数为10,应该表示为:桶在第2个字节,且位序列为001010,跨字节,如下图:
HyperLogLog学习总结_第1张图片

你可能感兴趣的:(redis,redis)