Redis之使用HyperLogLog统计网站UV

一句话:HyperLogLog用来统计一个很大很大的数据集(海量数据)的基数,是一个占用空间极低的set,省空间版的set

Redis在2.8.9版本中添加了HyperLogLog数据结构

1.区分UV和PV:

UV:Unique Vistor    独立访问量    1天内同一个用户多次访问该网站,只记录一次

PV:Page View  页面访问量,访问一次页面,记录一次,多次打开这个页面,记录多次PV,用来衡量网站的流量

所以PV往往会比UV大,UV/PV这个比值可以看出来一个用户访问这个网站是点完一次就走,还是在这个网站中浏览了很多页面

2.什么是基数?

一个数据集是{1,3,5,7,5,7,8},那么这个数据集的基数集就是{1,3,5,7,8},这个数据集的基数就是5(也就是说数据集去重后的元素个数

所以HyperLogLog和Set很像,但是如果一条key-value键值对的value是set,当set中几百万条数据的时候,这条key-value键值对很耗费空间

3.为什么用HyperLogLog来统计基数而不是用其他的来统计呢?节省内存

比如统计1亿个数据的基数,如果用set来存储这1亿个数据,占用的空间内存非常大,但是

单个HyperLogLog的内存永远小于16kb(内存低的令人发指,作为代价,其结果可能有一定的误差,有小于0.81%的误差,这点误差对于UV统计来说,是完全可以忽略的,比如10000个人,差了80个人,这点误差可以忽略不计的)

4.实际中如何使用HyperLogLog

HyperLogLog只有三个命令:PFADD,PFCOUNT,PFMERGE

(1)添加元素

Pfadd test1  e1 e2 e3 e4 e5

key你自己选一个名字(比如叫test1),后面可以插入1亿个用户id

(2)统计元素的基数

Pfcount  test1

(3)现在如果有两个key,都是HyperLogLog类型的,将这两个key合并一下(合并30天的UV,就可以得到一个月的UV,关键是就算把365天,一年的UV合并起来,内存大小都不会超过16kb)

@Test
public void  testHyperLogLog()
{
    String[] users=new String[1000000];

    for(int i=0;i<=1000000;i++)
    {
        users[i]="user_"+i;
         
        stringRedisTemplate.opsForHyperLogLog().add("test1",user[i]);
         
    }

    System.out.println(stringRedisTemplate.opsForHyperLogLog().size("test1"));
}

 插入了100 0000一百万条数据,最后先是size=997593 ,有一定的误差,但是误差不大,然后内存大小为14KB,确实没有超过16KB

合并多个HyperLogLog成1个HyperLogLog:

下面合并test1,test2,test3  3个HyperLogLog成一个HyperLogLog,新HyperLogLog叫做test4

stringRedisTemplate.opsForHyperLogLog().add("test1","ip1","ip2","ip3");


stringRedisTemplate.opsForHyperLogLog().add("test2","ip1","ip2","ip3","ip4","ip5");


stringRedisTemplate.opsForHyperLogLog().add("test3","ip4","ip5","ip6","ip7","ip8");


stringRedisTemplate.opsForHyperLogLog().union("test4","test1","test2","test3");

最终如果想要统计每一天的UV,可以将日期作为key,这一天访问网站的客户端ip地址作为value

你可能感兴趣的:(redis,redis)