HyperLogLog

2021-05-08  本文已影响0人  缘木与鱼

HyperLogLog

一般评估一个网站的访问量,有几个主要的参数:

一般来说,pv或者uv的统计,可以自己来做,也可以借助第三方工具,比如: cnzz,友盟等。

如果自己实现,pv比较简单,可以直接通过Redis 计数器实现。但是 uv不一样,uv涉及到另一个问题: 去重。

首先需要在前端给每一个用户生成一个唯一 id,无论是登录用户还是未登录用户,都要有一个唯一id,这个 id 伴随着请求一起到达后端,在后端我们通过 set 集合中的 sadd 命令来存储这个 id,最后通过 scard 统计集合大小,进而得出 uv 数据。

如果是千万级别的 UV,需要的存储空间就非常惊人。而且,像 UV 统计这种,一般也不需要特别精确,800w 的 uv 和 803w 的 uv,其实差别不大。所以,我们要介绍今天的主角---HyperLogLog。

Redis 中提供的 HyperLogLog 就是专门用来解决这个问题的,HyperLogLog 提供了一套不怎么精确但是够用的去重方案,会有误差,官方给出的误差数据是 0.81%,这个精确度,统计 UV 够用了。

HyperLogLog 主要提供了两个命令:pfadd 和 pfcount。

pfadd 用来添加记录,类似于 sadd ,添加过程中,重复的记录会自动去重。
pfcount 则用来统计数据。

数据量少的时候看不出来误差。

127.0.0.1:6379> pfadd uv1 u1 u2 u3
(integer) 1
127.0.0.1:6379> pfcount uv1
(integer) 3
127.0.0.1:6379> pfadd uv1 u1 u2 u3 u3 u2 u1 u4 u5
(integer) 1
127.0.0.1:6379> pfcount uv1
(integer) 5
127.0.0.1:6379> 
127.0.0.1:6379> pfcount uv
(integer) 994
127.0.0.1:6379> pfmerge uv1 uv
OK
127.0.0.1:6379> pfcount uv1
(integer) 994
127.0.0.1:6379> 

在 Java 中,我们多添加几个元素:

public class HyperLogLog {

    public static void main(String[] args) {
        Redis redis = new Redis();
        redis.execute(jedis -> {
            for (int i = 0; i< 1000; i++){
                jedis.pfadd("uv", "u" + i, "u" + (i+1));
            }
            long uv = jedis.pfcount("uv");
            System.out.println(uv);
        });
    }
}

理论值是1001,而实际运行值为 994 ,有误差,但可以在接收到范围内。

除了 pfadd 和 pfcount 之外,还有一个命令, pfmerge, 合并多个统计结果,在合并的过程中,会自动去重多个集合中重复的元素。

上一篇 下一篇

猜你喜欢

热点阅读