1,概述
在当今数字化时代,对于网站和应用程序的运营者而言,了解其用户的行为和习惯是至关重要的。其中,衡量页面的独立访客数量(UV)是评估网站流量和用户参与度的重要指标之一。然而,当面对海量访问数据时,传统的计数方法可能变得低效且成本高昂。
为解决这一挑战,Redis 提供了一种高效的解决方案:HyperLogLog。HyperLogLog 是一种基数估算算法,能够在常量时间内对集合中不同元素的近似数量进行快速估算。本文就来详细介绍下如何使用 Redis 统计海量 UV。
2,PV、UV 是什么?
PV(Page Views)是页面浏览量,指的是网站或应用程序页面被访问的次数。每一次页面的加载都被视为一个页面浏览量,无论是否为同一用户。
UV(Unique Visitors)是独立访客数量,指的是访问网站或应用程序的唯一用户数量。UV通常用于衡量网站或应用程序的独立用户群体规模,而不考虑他们的访问频率。PV 和 UV 是衡量网站或应用程序流量和用户参与度的重要指标之一。
3,Hyperloglog算法
HyperLogLog 是一种基数估算算法,可以用于快速计算一个集合中的不同元素数量的近似值。hyperloglog 算法,利用非常少的空间,实现比较大的数据量级统计;比如我们前面在介绍 bitmap 的过程中,说到了日活的统计,当数据量达到百万时,最佳的存储方式是 hyperloglog,
hyperloglog通常是用来非精确的计数统计,当时使用的是 bitmap 来作为数据统计,然而当 userId 分散不均匀,小的特别小,大的特别大的时候,并不适用
在数据量级很大的情况下,hyperloglog的优势非常大,它所占用的存储空间是固定的2^14 下图引用博文《用户日活月活怎么统计》
4,统计原理
在使用 HyperLogLog 统计页面 UV 时,我们可以将每个访问者的 IP 地址作为一个元素加入到 HyperLogLog 中,然后通过计算 HyperLogLog 中元素数量的近似值来估计页面的唯一访问者数量。使用 HyperLogLog 进行日活统计的设计思路比较简单
1,每日生成一个 key,
2,某个用户访问之后,执行 pfadd key userId
3,统计总数: pfcount key
关于 HyperLogLog 的原理我这里也不进行详细赘述,说实话那一套算法以及调和平均公式我自己也没太整明白;下面大致说一下我个人的朴素理解
Redis 中的 HyperLogLog 一共分了2^14=16384个桶,每个桶占 6 个 bit
一个数据,塞入 HyperLogLog 之前,先 hash 一下,得到一个 64 位的二进制数据
取低 14 位,用来定位桶的 index
高 50 位,从低到高数,找到第一个为 1 出现的位置 n若桶中值 > n,则丢掉反之,则设置桶中的值为 n
那么怎么进行计数统计呢?
拿所有桶中的值,代入下面的公式进行计算
5,代码实现
import redis.clients.jedis.Jedis;
public class HyperLogLogExample {
public static void main(String[] args) {
// 连接 Redis 服务器
Jedis jedis = new Jedis("localhost");
// 创建一个 HyperLogLog 实例
String hyperLogLogKey = "unique_users";
// 模拟用户访问行为,向 HyperLogLog 中添加元素
jedis.pfadd(hyperLogLogKey, "user1", "user2", "user3", "user4");
// 获取 HyperLogLog 的基数估计结果
long estimatedCount = jedis.pfcount(hyperLogLogKey);
System.out.println("Estimated unique users: " + estimatedCount);
// 模拟新的用户访问
jedis.pfadd(hyperLogLogKey, "user5", "user6", "user7");
// 更新基数估计结果
estimatedCount = jedis.pfcount(hyperLogLogKey);
System.out.println("Updated estimated unique users: " + estimatedCount);
// 关闭 Redis 连接
jedis.close();
}
}