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在内存的占用量上有很大的优势。

 

posted @ 2018-01-03 01:32  明王不动心  阅读(2146)  评论(0编辑  收藏  举报