Redis(十) -- Redis数据类型(七) -- HyperLogLog

1. 业务场景:

HyperLogLog常用于大数据量的统计,比如页面访问量统计或者用户访问量统计。

  1. 需求:要统计一个页面的访问量(PV)
    1. 方案:直接用redis计数器或者直接存数据库都可以
  2. 需求:要统计一个页面的用户访问量(UV),即:一个用户一天内如果访问多次的话,也只能算一次
    1. 方案:可能会想到用SET集合来做,因为SET集合是有去重功能的,key存储页面对应的关键字,value存储对应userId
  3. 需求:假如有几千万访问量,为了统计一个访问量,要频繁创建SET集合对象。
    1. 方案:针对大访问量需要进行统计的问题,redis实现了一种HyperLogLog算法。

2. 简介

Redis HyperLogLog是用来做技术统计的算法,优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的,并且是很小的。

在redis中,每个hyperLogLog键只需要花费12KB内存,记可以计算接近2^64个不同元素的基数。这和计算基数时,元素越多耗费内存越多的集合形成鲜明对比。

但是,由于HyperLogLog只会根据输入元素来计算基数,而不会存储输入元素本书,所以HyperLogLog不能像集合那样,返回输入的各个元素。

2.1 什么是基数

比如数据集{1,3,5,7,5,7,8}的基数集为{1,3,5,7,8},基数(不重复元素个数)为5。基数就是在误差可接受范围内,快速计算基数。

3. 应用场景:

统计注册 IP 数

统计每日访问 IP 数

统计页面实时 UV 数

统计在线用户数

统计用户每天搜索不同词条的个数

说明:基数不大,数据量不大就用不上,会有点大材小用浪费空间

有局限性,就是只能统计基数数量,而没办法去知道具体的内容是什么

和bitmap相比,属于两种特定统计情况,简单来说,HyperLogLog 去重比 bitmap 方便很多

一般可以bitmap和hyperloglog配合使用,bitmap标识哪些用户活跃,hyperloglog计数

4. 总结:

  1. HyperLogLog是一种算法,并非redis独有
  2. 目的是做基数统计,故不是集合,不会保存元数据,只记录数量而不是数值。
  3. 耗空间极小,支持输入非常体积的数据量
  4. 核心是基数估算算法,主要表现为计算时内存的使用和数据合并的处理。最终数值存在一定误差
  5. redis中每个hyperloglog key占用了12K的内存用于标记基数
  6. pfadd命令并不会一次性分配12k内存,而是随着基数的增加而逐渐增加内存分配;而pfmerge操作则会将sourcekey合并后存储在12k大小的key中,这由hyperloglog合并操作的原理(两个hyperloglog合并时需要单独比较每个桶的值)可以很容易理解。
  7. 误差说明:基数估计的结果是一个带有 0.81% 标准错误(standard error)的近似值。是可接受的范围
  8. Redis 对 HyperLogLog 的存储进行了优化,在计数比较小时,它的存储空间采用稀疏矩阵存储,空间占用很小,仅仅在计数慢慢变大,稀疏矩阵占用空间渐渐超过了阈值时才会一次性转变成稠密矩阵,才会占用 12k 的空间
  9. HyperLogLog算法一开始就是为了大数据量的统计而发明的,所以很适合那种数据量很大,然后又没要求不能有一点误差的计算,HyperLogLog 提供不精确的去重计数方案,虽然不精确但是也不是非常不精确,标准误差是 0.81%,不过这对于页面用户访问量是没影响的,因为这种统计可能是访问量非常巨大,但是又没必要做到绝对准确,访问量对准确率要求没那么高,但是性能存储方面要求就比较高了,而HyperLogLog正好符合这种要求,不会占用太多存储空间,同时性能不错。

5. 命令:

1.pfadd:将除了第一个参数以外的参数存储到以第一个参数为变量名的HyperLogLog结构中

  • 格式PFADD key element [element ...]
  • 这个命令的一个副作用是它可能会更改这个HyperLogLog的内部来反映在每添加一个唯一的对象时估计的基数(集合的基数).
  • 如果一个HyperLogLog的估计的近似基数在执行命令过程中发了变化, PFADD 返回1,否则返回0,如果指定的key不存在,这个命令会自动创建一个空的HyperLogLog结构(指定长度和编码的字符串).
  • 如果在调用该命令时仅提供变量名而不指定元素也是可以的,如果这个变量名存在,则不会有任何操作,如果不存在,则会创建一个数据结构(返回1)
  • 返回值:如果 HyperLogLog 的内部被修改了,那么返回 1,否则返回 0
  • 复杂度:O(1)
redis> PFADD hll a b c d e f g
(integer) 1
redis> PFCOUNT hll
(integer) 7

2.pfcount:返回存储在HyperLogLog结构体的该变量的近似基数

  • 格式PFCOUNT key [key ...]
  • 当参数为一个key时,返回存储在HyperLogLog结构体的该变量的近似基数,如果该变量不存在,则返回0.
  • 参数为多个key时,返回这些HyperLogLog并集的近似基数,这个值是将所给定的所有key的HyperLoglog结构合并到一个临时的HyperLogLog结构中计算而得到的.
  • HyperLogLog可以使用固定且很少的内存(每个HyperLogLog结构需要12K字节再加上key本身的几个字节)来存储集合的唯一元素.
  • 返回的可见集合基数并不是精确值, 而是一个带有 0.81% 标准错误(standard error)的近似值.
  • 例如为了记录一天会执行多少次各不相同的搜索查询, 一个程序可以在每次执行搜索查询时调用一次PFADD, 并通过调用PFCOUNT命令来获取这个记录的近似结果.
  • 注意: 这个命令的一个副作用是可能会导致HyperLogLog内部被更改,出于缓存的目的,它会用8字节的来记录最近一次计算得到基数,所以PFCOUNT命令在技术上是个写命令
  • 返回值:添加的唯一元素的近似数量
  • 复杂度:O(1) with every small average constant times when called with a single key. O(N) with N being the number of keys, and much bigger constant times, when called with multiple keys
redis> PFADD hll foo bar zap
(integer) 1
redis> PFADD hll zap zap zap
(integer) 0
redis> PFADD hll foo bar
(integer) 0
redis> PFCOUNT hll
(integer) 3
redis> PFADD some-other-hll 1 2 3
(integer) 1
redis> PFCOUNT hll some-other-hll
(integer) 6

性能

当调用PFCOUNT命令时指定一个key为参数,性能表现很好,甚至和处理一个HyperLogLog所需要的时间一样短.这可能和PFCOUNT命令能够直接使用缓存的的估计基数有关,大多数的PFADD也不会更新任何寄存器,所以这个值也很少被更改.理论上能达到每秒几百次操作.

当调用PFCOUNT命令时指定多个key,由于要在多个HperLogLog结构中执行一比较慢合并操作,而且这个通过并集计算得到的基数是不能够被缓存, PFCOUNT命令还要消耗毫秒量级的时间来进行多个key的并集操作,消耗的时间会比较长一些,所以不要滥用这种多个key的方式.

使用者需要明白这个命令来处理1个key和多个key执行的语义是不同的,并且执行的性能也不相同.

更多的信息请参考这篇文章. 源代码 hyperloglog.c文件也很简单易理解, 包含了稀松与密集两种实现的编码.

3.pfmerge:将多个 HyperLogLog 合并(merge)为一个 HyperLogLog

  • 格式PFMERGE destkey sourcekey [sourcekey ...]
  • 合并后的 HyperLogLog 的基数接近于所有输入 HyperLogLog 的可见集合(observed set)的并集.
  • 合并得出的 HyperLogLog 会被储存在目标变量(第一个参数)里面, 如果该键并不存在, 那么命令在执行之前, 会先为该键创建一个空的
  • 返回值:OK
  • 复杂度:O(N) to merge N HyperLogLogs, but with high constant times
redis> PFADD hll1 foo bar zap a
(integer) 1
redis> PFADD hll2 a b c foo
(integer) 1
redis> PFMERGE hll3 hll1 hll2
OK
redis> PFCOUNT hll3
(integer) 6
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值