【SpringBoot DB 系列】Redis 高级特性之 HyperLoglog
hyperloglog 算法,利用非常少的空间,实现比较大的数据量级统计;比如我们前面在介绍 bitmap 的过程中,说到了日活的统计,当数据量达到百万时,最佳的存储方式是 hyperloglog,本文将介绍一下 hyperloglog 的基本原理,以及 redis 中的使用姿势
I. 基本使用
1. 配置
我们使用 SpringBoot 2.2.1.RELEASE
来搭建项目环境,直接在pom.xml
中添加 redis 依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> 复制代码
如果我们的 redis 是默认配置,则可以不额外添加任何配置;也可以直接在application.yml
配置中,如下
spring: redis: host: 127.0.0.1 port: 6379 password: 复制代码
2. 使用姿势
我们下来看使用姿势,原理放在后面说明
redis 中,hyperlolog
使用非常简单,一般就两个操作命令,添加pfadd
+ 计数pfcount
;另外还有一个不常用的merge
a. add
添加一条记录
public boolean add(String key, String obj) { // pfadd key obj return stringRedisTemplate.opsForHyperLogLog().add(key, obj) > 0; } 复制代码
b. pfcount
非精准的计数统计
public long count(String key) { // pfcount 非精准统计 key的计数 return stringRedisTemplate.opsForHyperLogLog().size(key); } 复制代码
a. merge
将多个 hyperloglog 合并成一个新的 hyperloglog;感觉用的场景并不会特别多
public boolean merge(String out, String... key) { // pfmerge out key1 key2 ---> 将key1 key2 合并成一个新的hyperloglog out return stringRedisTemplate.opsForHyperLogLog().union(out, key) > 0; } 复制代码
3. 原理说明
关于 HyperLogLog 的原理我这里也不进行详细赘述,说实话那一套算法以及调和平均公式我自己也没太整明白;下面大致说一下我个人的朴素理解
Redis 中的 HyperLogLog 一共分了2^14=16384
个桶,每个桶占 6 个 bit
一个数据,塞入 HyperLogLog 之前,先 hash 一下,得到一个 64 位的二进制数据
- 取低 14 位,用来定位桶的 index
- 高 50 位,从低到高数,找到第一个为 1 出现的位置 n
- 若桶中值 > n,则丢掉
- 反之,则设置桶中的值为 n
那么怎么进行计数统计呢?
- 拿所有桶中的值,代入下面的公式进行计算
上面这个公式怎么得出的?
之前看到一篇文章,感觉不错,有兴趣了解原理的,可以移步: www.jianshu.com/p/55defda6d…
4. 应用场景
hyperloglog
通常是用来非精确的计数统计,前面介绍了日活统计的 case,当时使用的是 bitmap 来作为数据统计,然而当 userId 分散不均匀,小的特别小,大的特别大的时候,并不适用
在数据量级很大的情况下,hyperloglog
的优势非常大,它所占用的存储空间是固定的2^14
下图引用博文《用户日活月活怎么统计》
使用 HyperLogLog 进行日活统计的设计思路比较简单
- 每日生成一个 key
- 某个用户访问之后,执行
pfadd key userId
- 统计总数:
pfcount key