redis 高级数据类型之 HyperLogLog 算法详细介绍

HyperLogLog是一个专门为了计算集合的基数而创建的概率算法,对于一个给定的集合,HyperLogLog可以计算出这个集合的近似基数:近似基数并非集合的实际基数,它可能会比实际的基数小一点或者大一点,但是估算基数和实际基数之间的误差会处于一个合理的范围之内,因此那些不需要知道实际基数或者因为条件限制而无法计算出实际基数的程序就可以把这个近似基数当作集合的基数来使用。
摘要由CSDN通过智能技术生成

前面曾介绍过使用Redis集合构建唯一计数器,并将这个计数器用于计算网站的唯一访客IP。虽然使用Redis集合实现唯一计数器能够在功能上满足我们的要求,但是如果考虑得更长远一些,就会发现这个使用Redis集合实现的唯一计数器有一个明显的缺陷:随着被计数元素的不断增多,唯一计数器占用的内存也会越来越大;计数器越多,它们的体积越大,这一情况就会越严峻。

以计算唯一访客IP为例:

  • 存储一个IPv4格式的IP地址最多需要15个字节(比如"127.234.122.101")。

  • 根据网站的规模不同,每天出现的唯一IP可能会有数十万、数百万甚至数千万个。

  • 为了记录网站在不同时期的访客,并进行相关的数据分析,网站可能需要持续地记录每天的唯一访客IP数量,短则几个月,长则数年。

综合以上条件,如果一个网站想要长时间记录访客的IP,就必须创建多个唯一计数器。如果网站的访客比较多,那么它创建的每个唯一计数器都将包含大量元素,并因此占用相当一部分内存。

表7-1展示了不同规模的网站在不同时间段中,存储唯一访客IP所需的最大内存。可以看到,当网站的唯一访客数量达到1000万时,网站每个月就要花费4.5GB内存去存储唯一访客的IP,对于记录唯一访客IP数量这个简单的功能来说,这样的内存开销实在让人难以接受,并且这还只是存储IPv4地址的开销,随着IPv6地址的逐渐普及,计数器将来可能需要存储IPv6地址,那时它的开销还会再翻上几倍!

表7-1 不同规模的网站在使用集合记录访客唯一IP时所需的内存数量

在这里插入图片描述

在这里插入图片描述

为了高效地解决计算唯一访客IP数量这类问题,研究人员开发了很多不同的方法,其中一个就是本章要介绍的HyperLogLog算法。

1.1 HyperLogLog简介

HyperLogLog是一个专门为了计算集合的基数而创建的概率算法,对于一个给定的集合,HyperLogLog可以计算出这个集合的近似基数:近似基数并非集合的实际基数,它可能会比实际的基数小一点或者大一点,但是估算基数和实际基数之间的误差会处于一个合理的范围之内,因此那些不需要知道实际基数或者因为条件限制而无法计算出实际基数的程序就可以把这个近似基数当作集合的基数来使用。

HyperLogLog的优点在于它计算近似基数所需的内存并不会因为集合的大小而改变,无论集合包含的元素有多少个,HyperLogLog进行计算所需的内存总是固定的,并且是非常少的。具体到实现上,Redis的每个HyperLogLog只需要使用12KB内存空间,就可以对接近:264个元素进行计数,而算法的标准误差仅为0.81%,因此它计算出的近似基数是相当可信的。

本章将对Redis中HyperLogLog的各个操作命令进行介绍,通过使用这些命令,用户可以:

  • 对集合的元素进行计数。

  • 获取集合当前的近似基数。

  • 合并多个HyperLogLog,合并后的HyperLogLog记录了所有被计数集合的并集的近似基数。

在介绍HyperLogLog命令的同时,本章还会说明如何通过这些命令去实现一个只需要固定内存的唯一计数器,以及一个能够检测出重复信息的检查器。

1.2 PFADD:对集合元素进行计数

用户可以通过执行PFADD命令,使用HyperLogLog对给定的一个或多个集合元素进行计数:

PFADD hyperloglog element [element ...]

根据给定的元素是否已经进行过计数,PFADD命令可能返回0,也可能返回1:

  • 如果给定的所有元素都已经进行过计数,那么PFADD命令将返回0,表示HyperLog-Log计算出的近似基数没有发生变化。

  • 与此相反,如果给定的元素中出现了至少一个之前没有进行过计数的元素,导致HyperLogLog计算出的近似基数发生了变化,那么PFADD命令将返回1。

举个例子,通过执行以下命令,我们可以使用alphabets这个HyperLogLog对"a"、“b”、"c"这3个元素进行计数:

redis> PFADD alphabets "a" "b" "c"
(integer) 1

因为这是alphabets第一次对元素"a"、“b”、"c"进行计数,所以alphabets计算的近似基数将发生变化,并使PFADD命令返回1。

但是如果我们再次要求alphabets对元素"a"进行计数,那么这次PFADD命令将返回0,这是因为已经计数过的元素"a"并不会对alphabets计算的近似基数产生影响:

redis> PFADD alphabets "a"
(integer) 0

其他信息

复杂度:O(N),其中N为用户给定的元素数量。

版本要求:PFADD命令从Redis 2.8.9版本开始可用。

1.3 PFCOUNT:返回集合的近似基数

在使用PFADD命令对元素进行计数之后,用户可以通过执行PFCOUNT命令来获取HyperLogLog为集合计算出的近似基数:

PFCOUNT hyperloglog [hyperloglog ...]

比如,通过执行以下命令,我们可以获取到alphabets这个HyperLogLog计算出的近似基数:

redis> PFCOUNT alphabets
(integer) 3

PFCOUNT命令的返回值为3,这表示HyperLogLog算法认为alphabets目前已经计数过3个不同的元素。

另外,当用户给定的HyperLogLog不存在时,PFCOUNT命令将返回0作为结果:

redis> PFCOUNT not-exists-hyperloglog
(integer) 0
1.3.1 返回并集的近似基数

当用户向PFCOUNT传入多个HyperLogLog时,PFCOUNT命令将对所有给定的Hyper-LogLog执行并集计算,然后返回并集HyperLogLog计算出的近似基数。

比如,我们可以创建两个HyperLogLog,并分别使用这两个HyperLogLog去对两组字母进行计数:

redi
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个火星程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值