问题来源
常见去重统计的而方式
Set
通常使用跳表或树(红黑树、AVL树等)或哈希表等时间复杂度为O(logn)或O(1)的数据结构实现,在一般数据量下综合性能还是比较优秀,但在巨量数据量的情况下内存的消耗也是极其巨大的。
Bitmap——位图
bitmap是通过用位bit数组来表示各元素是否出现,每个元素对应一位,所需的总内存为N个bit。
但是现在,假设一个样本案例就是一亿个基数位值数据,一个样本就是一亿。
如果要统计1亿个数据的基数位值,大约需要内存100000000/8/1024/1024约等于12M,内存减少占用的效果显著。
这样得到统计一个对象样本的基数值需要12M。
如果统计10000个对象样本(1w个亿级),就需要117.1875G将近120G,可见在巨量数据的背景下使用bitmap,还是会出现向set那样的内存开销过高的问题,所以位图还是不太适用大量数据下的基数计数场景,但是bitmaps方法是精确计算的。
HyperLogLog是什么
去重统计功能的基数估计算法
用途
用于统计一个集合中不重复元素的个数,就是对集合去重复之后剩余元素的计算。不是集合也不保存数据,只是记录数量而不是具体内容。
特点
- 统计数量统计,不关注统计对象的内容和精准性。
- 内存开销低,Redis中的每个HyperLogLog只需要花费12KB内存,就可以计算2^64个不同元素的基数。
- 有误差,HyperLogLog是一种牺牲准确率来换取空间(因为概率算法不直接存储数据本身),对于不要求绝对准确的场景下可以使用。但是误差率只是
0.8125%
命令
| 命令 | 用法 |
|---|---|
| pfadd key element .... | 将所有元素添加到key中 |
| pfcount key | 统计key的估计值(不准确) |
| pfmerge new_key key1 key2 ... | 合并key到新key |
应用场景
很多计数类场景,比如 每日注册 IP 数、每日访问 IP 数、页面实时访问数 PV、访问用户数 UV等。