HyperLogLog
核心知识点:
1.HyperLogLog并不是一种数据结构,而是一种算法,可以利用极小的内存空间完成独立总数的统计。
2.命令:
a.padd:添加
b.pfcount:统计
c.pfmerge:合并
3.HyperLogLog内存占用虽然小,但是并不准确,而且只能计算独立总数。
HyperLogLog并不是一种新的数据结构(实际类型为字符串类型),而是一种基础算法,
通过HyperLogLog可以利用极小的内存空间完成独立总数的统计,数据集可以是IP、Email、ID等。
HyperLogLog提供了3个命令:pfadd、pfcount、pfmerge。
一、命令
1.添加
pfadd key element [element ... ]
pfadd用于向HyperLogLog添加元素,如果添加成功返回1:
127.0.0.1:6379> pfadd unique:ids "uuid-1" "uuid-2" "uuid-3" "uuid-4" (integer) 1
2.计算独立用户数
pfcount key [key ...]
pfcount用于计算一个或多个HyperLogLog的独立总数:
127.0.0.1:6379> pfcount unique:ids (integer) 4
如果此时再向其中个插入4条数据,一条是新的:
127.0.0.1:6379> pfadd unique:ids "uuid-1" "uuid-2" "uuid-3" "uuid-90" (integer) 1 127.0.0.1:6379> pfcount unique:ids (integer) 5
3.合并
pfmerge destkey sourcekey [sourcekey ... ]
pfmerge可以求出多个HyperLogLog的并集并赋值给destkey:
127.0.0.1:6379> pfadd 2016_03_05:unique:ids "uuid-1" "uuid-2" "uuid-3" "uuid-4" (integer) 1 127.0.0.1:6379> pfadd 2016_03_06:unique:ids "uuid-3" "uuid-4" "uuid-6" "uuid-8" (integer) 1 127.0.0.1:6379> pfmerge 2016_03_05_06:unique:ids 2016_03_05:unique:ids 2016_03_06:unique:ids OK 127.0.0.1:6379> pfcount 2016_03_05_06:unique:ids (integer) 6 #用户总数是6位,取并集
二、性能测试
可以使用上面命令测试出HyperLogLog在独立总数方面的优点和不足之处。
使用info mempry查看目前已使用内存:
127.0.0.1:6379> info memory # Memory used_memory:3769248 used_memory_human:3.59M #已使用3.59M ...
使用下面脚本向2016_05_01:unique:ids中插入100万条数据,每次插入1000条:
#!/bin/bash elements="" key="2016_05_01:unique:ids" for i in `seq 1 1000000` do elements="${elements} uuid-"${i} #字符串累加,每隔1000写入一次 if [[ $((i%1000)) == 0 ]]; then redis-cli pfadd ${key} ${elements} elements="" fi done
当完成上述操作之后,使用info memory再次查看:
127.0.0.1:6379> info memory # Memory used_memory:3780640 used_memory_human:3.61M ...
3.61-3.59=0.02M,大约只增长了20KB。
再次查看总数:
127.0.0.1:6379> pfcount 2016_05_01:unique:ids (integer) 999978 #不足100万条,有误差
可以看到pfcount对总数的统计是有误差的。
同样,我们往一个集合中插入同样的100万条数据,测试脚本如下:
#!/bin/bash elements="" key="2016_05_01:unique:ids:set" for i in `seq 1 1000000` do elements="${elements} uuid-"${i} if [[ $((i%1000)) == 0 ]]; then redis-cli sadd ${key} ${elements} > /dev/null elements="" fi done
再次查看内存使用情况:
127.0.0.1:6379> info memory # Memory used_memory:92194784 used_memory_human:87.92M ...
内存使用了大概84MB。用户统计数为:
127.0.0.1:6379> scard 2016_05_01:unique:ids:set (integer) 1000000 #准确的100万条
下表展示了集合类型和hyperLogLog的占用空间的对比:
可以看到HyperLogLog内存占用量小的惊人,但是用如此小空间来估算如此巨大的数据,
必然不是100%的正确,其中一定存在误差率。Redis官方给出的数字是0.81%的失误率。
HyperLogLog内存占用量非常小,但是存在错误率,开发者在进行数据结构选型时只需要确认如下两条即可:
- 只为了计算独立总数,不需要获取单条数据;
- 可以容忍一定误差率,毕竟HyperLogLog在内存的占用量上有很大的优势。