HyperLogLog in Redis

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lzx_victory/article/details/80200005

HyperLogLog 主要用于大量数据的一些统计以及合并工作.
本文主要简单的介绍一下HyperLogLog概念,以及简单介绍在Redis当中的实现.

让我们从一个故事讲起

抛硬币

现在我们抛硬币,每组8次,将每次为正面的硬币记为正,否则记为反.
那么我可以得到,随机的记录如下:

正正反正反正反正反正
正反反正反正反正反正
...

就这样一致抛下去,最终我们会有很多不同的结果的组.
现在就从概率学的角度看待这个问题,我们的得到正正正正正正正X要比得到正正正正XXXX难的多.
难的多,只是一个口语话的描述,说明我们就需要更多的实验组去获得这样一组数据.
这样我们就可以拿从起始位置算起连续的个数去估计当前的数据的数量.

现在我们将每组开头连续的正记录次数,第一组为2,第二组为1.
那么我们可以预估当前的不同的元素个数为2^2

当我们的试验次数足够多的时候我们可以得出一组都为正,那么此时的试验不同的元素就变为了2^8.

由此可以得出的结论是当足够随机而且实验次数足够多的时候,我们就可以用这样的方法来估计不同元素数量.
当然这样是有误差的,一般情况下误差控制在1%以下,非精准要求的业务可以采用这个算法,可以极大的提升空间存储的效率.
HyperLogLog 采取了更好的策略使得更好的

HyperLogLog Algorithm

The basis of the HyperLogLog algorithm is the observation that the cardinality of a multiset of uniformly distributed random numbers can be estimated by calculating the maximum number of leading zeros in the binary representation of each number in the set. If the maximum number of leading zeros observed is n, an estimate for the number of distinct elements in the set is 2n. -From wiki

HyperLogLog算法是在一组二进制数的集合中观察一致连续随机数字的基数,基数是使用最大前导0的个数进行估算集合中的元素的个数.如果最大前导0是n(位置从1开始计算)位置,那么估算在集合当中唯一的元素个数就是2^n个.

The simple estimate of cardinality obtained using the algorithm above has the disadvantage of a large variance. In the HyperLogLog algorithm, the variance is minimised by splitting the multiset into numerous subsets, calculating the maximum number of leading zeros in the numbers in each of these subsets, and using a harmonic mean to combine these estimates for each subset into an estimate of the cardinality of the whole set.

这样简单的估算有个缺点就是方差很大.在HyperLogLog当中,方差可以通过将集合分割多个子集被最小化,分别计算在每个子集当中最大前导0的个数.根据每个子集的估算的值得到调和平均数去估算整个集合的基数.

分子集:

以8位举例

00|100000
10|001000
01|001000
11|010000

前两位作为子集的标志,后边6位计算最大位数前导0,这里的前导0是去掉子集的标志位的最大位数.

Redis的实现

首先值可以被hash为64位二进制数,集合当中可以放入字符串,被hahs成64位数,Redis使用的前14位作为子集的标志,用来定位内存当中的偏移值(offset).
那么我们就有2^16(16384)个子集(Bucket).误差为0.81%
剩下的50位计算最大前导0的位数,Redis每个Bucket只用6位存储最大前导0的个数,最大是50.

因此得到 16384 * 6 / 8 = 12288个字节.
因此数据内容格式如下:

 110010  110011 000000  -->numbers of leading zero
    0             1             2    --> subset tag,offset = 6 * subset tag 

猜你喜欢

转载自blog.csdn.net/lzx_victory/article/details/80200005