Redis中HyperLogLog的使用

文章介绍了HyperLogLog算法在互联网流量统计中的应用,尤其是UV和PV的去重问题,展示了如何使用Redis中的相关命令进行操作,并测试了内存占用和统计精度。

目录

前言

HyperLogLog


前言

在学习HyperLogLog之前,我们需要先学习两个概念

  • UV:全称Unique Visitor,也叫独立访客量,是指通过互联网访问、浏览这个网页的自然人。1天内同一个用户多次访问该网站,只记录1次。
  • PV:全称Page View,也叫页面访问量或点击量,用户每访问网站的一个页面,记录1次PV,用户多次打开页面,则记录多次PV。往往用来衡量网站的流量。

如果UV在服务端做会很麻烦,因为每次都需要判断该用户是否已经统计过了,因此需要保存统计过的用户信息,如果都保存在Redis中,大型网站的数据量会非常大这种实现方案并不现实。因此,我们需要使用HyperLogLog算法。

HyperLogLog

该算法又可以叫做HLL算法,是从LogLog算法派生的概率算法,用于确定非常大的集合的基数,而不需要存储其所有值,Redis中的HLL是基于String结构实现的,单个HLL的内存占用永远不会超过16k,相应的代价是测量结果是概率性的,存在一定误差,但是可以忽略不计。

对应的命令如下

# 添加用户ip
PFADD key element [element ...]
# 统计访问量,在存在多个key的情况下,会对多个key的访问用户进行去重后再统计
PFCOUNT key [key ...]
# 合并统计量
PFMERGE destkey sourcekey [sourcekey ...]

接下来我们对该方法进行测试,首先我们对 hll1 这个key进行插入,插入结果如下

那么接下来插入key为 hll2 的数据,执行结果结果如下

在 key 为 hll2 的数据完全包含了key为 hll1 的值时,我们对两个 key 进行联合统计,观察输出结果

可以看到,我们的统计结果是进行了去重后再进行统计的。那么接下来测试合并方法

hll2 的数据会合并到 hll1 中,该方法的存在,我们可以设置ip访问时设置 key 为年月日,这样我们可以通过合并每天的key来统计每月的活跃人数。接下来我们测试HLL的内存占用情况

首先是我们先获取没有存储100w数据情况时的内存使用情况,需要注意的时,该值为字节值,需要我们自己转化为kb

测试代码如下,我们需要创建100w的对象来模拟访问量通过HLL存储,我们测试Redis的占用情况

@Test
public void test01() throws Exception {
    String[] str = new String[1000];
    int j =0;
    for (int i = 0; i < 1000000; i++) {
        j = i%1000;
        str[j] = "user"+i;
        if (j == 999){
            stringRedisTemplate.opsForHyperLogLog().add("hll1",str);
        }
    }
    Long count = stringRedisTemplate.opsForHyperLogLog().size("hll1");
    System.out.println(count);
}

执行完测试代码后的内存占用情况以及统计结果如下,内存占用变为 900992,统计次数为 1001788,可以看到存在一定误差,但是对于100w数据来说基本可以忽略不计。

计算添加完数据后的内存占用(900992-886608)/1024 ≈ 14k。并且无论执行多少次添加数据操作,只要对象不发生改变,永远统计到的数量为1001788。

### Redis HyperLogLog 数据结构和使用方法 Redis HyperLogLog 是一种基于概率算法的数据结构,用于高效统计唯一值的数量。它特别适合在内存有限的情况下处理大规模数据集的基数统计问题[^1]。HyperLogLog 的核心优势包括极低的内存占用、高效的插入和查询操作以及可接受的误差范围。 #### 1. Redis HyperLogLog 的基本概念 Redis HyperLogLog 使用概率算法来近似统计集合中唯一元素的数量。其主要特点如下: - **内存占用**:每个 HyperLogLog 结构通常只需要 12 KB 到 16 KB 的内存,无论数据量有多大[^3]。 - **时间复杂度**:插入操作和获取统计结果的时间复杂度均为 O(1)。 - **误差范围**:HyperLogLog 的统计结果是近似的,但误差范围通常在 0.5% 以内。 #### 2. Redis HyperLogLog 的典型应用场景 HyperLogLog 常用于需要统计唯一值数量的场景,例如: - 统计独立访客数量[^4]。 - 记录和统计用户的购物足迹[^2]。 - 在大数据场景下进行去重统计[^4]。 #### 3. Redis HyperLogLog使用方法 以下是 Redis HyperLogLog 的常用命令及其用法示例: ##### (1) `PFADD` `PFADD` 命令用于向 HyperLogLog 中添加一个或多个元素。 ```python # 添加单个元素 redis.pfadd("hyperloglog_key", "element1") # 添加多个元素 redis.pfadd("hyperloglog_key", "element1", "element2", "element3") ``` ##### (2) `PFCOUNT` `PFCOUNT` 命令用于返回 HyperLogLog 中估计的唯一元素数量。 ```python # 获取唯一元素数量 count = redis.pfcount("hyperloglog_key") print(f"Unique elements count: {count}") ``` ##### (3) `PFMERGE` `PFMERGE` 命令用于将多个 HyperLogLog 合并为一个新的 HyperLogLog。 ```python # 合并两个 HyperLogLog redis.pfmerge("merged_hyperloglog_key", "hyperloglog_key1", "hyperloglog_key2") ``` #### 4. 示例代码 以下是一个完整的 Python 示例,展示如何使用 Redis 和 Lettuce 客户端库来操作 HyperLogLog 数据结构。 ```python import redis # 连接 Redis 服务器 r = redis.StrictRedis(host='localhost', port=6379, db=0) # 添加元素到 HyperLogLog r.pfadd("unique_visitors", "user1") r.pfadd("unique_visitors", "user2") r.pfadd("unique_visitors", "user3") # 获取唯一访客数量 count = r.pfcount("unique_visitors") print(f"Number of unique visitors: {count}") # 创建另一个 HyperLogLog 并合并 r.pfadd("unique_visitors_2", "user2") r.pfadd("unique_visitors_2", "user4") # 合并两个 HyperLogLog r.pfmerge("merged_unique_visitors", "unique_visitors", "unique_visitors_2") # 获取合并后的唯一访客数量 merged_count = r.pfcount("merged_unique_visitors") print(f"Number of merged unique visitors: {merged_count}") ``` #### 5. 注意事项 - HyperLogLog 的结果是近似的,因此在对精确性要求极高的场景中需要谨慎使用[^3]。 - 如果需要更高的精度,可以考虑其他数据结构,如布隆过滤器(Bloom Filter)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zmbwcx2003

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值