# 书接上回
上一篇我们学习的 bitmap 这一 “数据类型” 。其内部是由 sds 这种种数据结构编码的。
如果不记得了,那就来坐穿梭机回去看看吧。 开始穿梭
接下来,我们继续学习一个新的 "数据类型" , 位图, HyperLogLogs .(注意啦,数据类型,我又加了引号!!)
# HyperLogLogs 简介
HyperLogLog 是一种概率数据结构,用于对唯一事物进行计数(从技术上讲,这是指估计集合的基数)。
注意哦, HyperlogLog 其实是一种基数计数算法,并非 Redis 独有的。
通常,对唯一项目进行计数需要使用与要计数的项目数量成比例的内存量,因为您需要记住过去已经看到的元素,以避免多次对其进行计数。但是,有一组算法会以内存换取精度:以 Redis 实施为例,您得出的带有标准误差的估计度量最终会小于 1% 。
该算法的神奇之处在于,您不再需要使用与所计数项目数量成比例的内存量,而可以使用恒定数量的内存!在最坏的情况下为 12k 字节,如果您的 HyperLogLogs 看到的元素很少,而且少得多。
Redis 中的 HyperLogLog 尽管在技术上是不同的数据结构,但被编码为 Redis字符串 ( sds ),因此您可以调用 GET 来序列化 HyperLogLogs ,然后调用 SET 来将其反序列化回服务器。这里我们在文末会大体翻一下源码。
接下来我们先看一下 HyperLogLog 有什么应用场景。
# HyperLogLog 的应用场景
根据 HyperLogLog 的特性来看,使用了一种概率性计数的功能,这样的功能有一个特点就是当数据特别大的时候,其统计的值是不准确的。什么意思呢?
就是比如统计一个网站的 PV , PV 数值是 123456789 或者 123456000 这两者的值对于管理者来讲是一样的。对于一些对精度要求不准确而且数据量很大的场景是非常适合的。
比如以下场景:计算网站的 PV,UV,统计日活,月活,统计用户每天搜索的词条数等等。
# HyperLogLog 的常用命令
HyperLogLog 应该是 Redis 所有结构中命令最少的了,只有三个命令。
PFADD key element [element ...]
添加元素。
如果一个 HyperLogLog 的估计的近似基数在执行命令过程中发了变化, PFADD 返回 1 ,否则返回 0 ,如果指定的 key 不存在,这个命令会自动创建一个空的 HyperLogLog 结构(指定长度和编码的字符串).
1 | 127.0.0.1:6379> pfadd k96 v1 v2 v3 |
PFCOUNT key [key ...]
当参数为一个 key 时,返回存储在 HyperLogLog 结构体的该变量的近似基数,如果该变量不存在,则返回 0 .
当参数为多个 key 时,返回这些 HyperLogLog 并集的近似基数,这个值是将所给定的所有 key 的 HyperLoglog 结构合并到一个临时的 HyperLogLog 结构中计算而得到的.
1 | 127.0.0.1:6379> pfadd k97 v1 v2 v3 v4 |
刚才说了, HyperLogLog 只是存储总数的一种结构,而且其值也会和实际值有偏差。我们一起来验证一下这个结果
我们往 Redis 中插入 10000 条数据,查看其 pfcount 的值是多少。
使用下面这个脚本去插入 ( java 实现)。公众号回复 RedisClient 可以获取完整源码。
1 | String host = "10.1.14.159"; |
插入完成之后,如下图,我们可以看到 pfCount 的结果是 9988 .

如果不相信我们可以 在 shell 里看看。
1 | 127.0.0.1:6379> pfcount k97 |
我这次测试正好相等,其实由于脚本的问题呢,从程序里获取的值和 shell 里获取的值,可能不一样,这种怎么解决呢? 使用脚本单独再执行一次,就会一样了。具体原因,不赘述了。
好了,我们插入了 10000 次,但是得出的值却是 9988 , 这也就验证了其不精确性。
PFMERGE destkey sourcekey [sourcekey ...]
将多个 HyperLogLog 合并( merge )为一个 HyperLogLog , 合并后的 HyperLogLog 的基数接近于所有输入 HyperLogLog 的可见集合( observed set )的并集.
合并得出的 HyperLogLog 会被储存在目标变量(第一个参数)里面, 如果该键并不存在, 那么命令在执行之前, 会先为该键创建一个空的 HyperLogLog .
1 | 127.0.0.1:6379> pfadd k98 v1 v2 v3 |
以上就是 HyperLogLog 的命令,老规矩我们下一步来看看 HyperLogLog 在 Redis 中是怎么实现的。
# HyperLogLog 的结构
在 Clion 中直接查找 hyperloglog ,就是 hyperloglog 的实现了。

我们可以看到有一个 struct
1 | struct hllhdr { |
这个就是 HyperLogLog 的存储结构了。这里大家大体有个印象就可以了。HyperLogLog 是一种基数估算算法的实现。后面我们会介绍这种基数估算法。
# 预告
最后一个 数据类型 geohash (多维空间点索引算法)!!!
# 最后
希望与你一起遇见更好的自己
