学习目标:
1、了解HyperLogLog作用
2、掌握redis对HyperLogLog的命令的支持
学习过程:
一、了解HyperLogLog算法
基数估算时大数据应用场景中最常见的一应用,比如如果我们需要统计一天内的独立用户数,一个用户在可能会多次的访问,但是我们不需要重复的累计,最后统计的数量只要误差不太大就行了,那么我们是否需要记录每一个用户呢,事实上我们需要获得的时用户数即可,如果有几十亿用户,全部记录起来再统计,不仅会耗费大量的储存空间,也会影响统计的效率。
HyperLogLog 时一种基数统计的算法,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的,redis每一个HyperLogLog元素最多就是12K,HyperLogLog只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能返回输入的各个元素。
HyperLogLog 算法给出的基数并不是精确的,可能会比实际稍微多一些或者稍微少一些,但会控制在合理的范围之内。
二、命令的使用
redis对HyperLogLog算法的支持也非常简单,一般也就是三个命令
pfadd 、 pfcount 、 pfmerge
127.0.0.1:6379> pfadd uname liu #添加一个进去
(integer) 1
127.0.0.1:6379> pfadd uname bao
(integer) 1
127.0.0.1:6379> pfcount uname #执行统计
(integer) 2
127.0.0.1:6379> pfadd cname liu #另外一个HyperLogLog元素,包含和uname一样的liu的值
(integer) 1
127.0.0.1:6379> pfadd cname hello
(integer) 1
127.0.0.1:6379> pfcount cname
(integer) 2
127.0.0.1:6379> pfmerge uname cname # 合并
OK
127.0.0.1:6379> pfcount uname #在统计
(integer) 3
看着上面的数量好像也是挺准确的,我们使用java代码添加更多的数量尝试一下,Java代码如下:
@Test
public void testHyperLogLogSet(){
HyperLogLogOperations vo = template.opsForHyperLogLog();
for (int i = 0; i < 10000; i++) {
vo.add("books", "a"+i,"b"+i,"c"+i);
}
for (int i = 0; i < 10000; i++) {
vo.add("desks", "a"+i,"b"+i,"c"+i);
}
}
@Test
public void testHyperLogLogCount(){
HyperLogLogOperations vo = template.opsForHyperLogLog();
System.out.println("books="+vo.size("books"));
System.out.println("desks="+vo.size("desks"));
vo.union("alls","books", "desks");
System.out.println("alls="+vo.size("alls"));
}
最后输出如下:
books=30067
desks=30067
alls=30067
可以看到并不是30000,还是会有点偏差的。