UV:unique visitor,独立访客,数据去重
DV:distinct value,去重统计,如上面的UV。
用redis的set去重,用户多时,比如微信月活10亿,就会占用很多内存。
用HyperLogLog,最多12k内存,可以统计2^64=100亿亿个值,当然是模糊统计,误差0.81%。
对于UV,可以有误差,比如10亿和10亿一千万,差别不大。
使用
public Object publishHyperLog() {
HyperLogLogOperations<String, String> hyperLogLogOperations = redisTemplate.opsForHyperLogLog();
hyperLogLogOperations.delete(RedisConstant.STATIS_UV);
//可以去重
for (int j = 0; j < 2; j++) {
for (int i = 0; i < 1000; i++) {
hyperLogLogOperations.add(RedisConstant.STATIS_UV, i + "");
}
}
Long size = hyperLogLogOperations.size(RedisConstant.STATIS_UV);
System.out.println(size);//1000
return size;
}
原理
把数值hash成64位bit串,低14位作为桶的编号,共有2^14=16384个桶。
高50位寻找第一个1出现的位置,估计数据基数。
然后所有桶的基数求调和平均数,分桶为了降低误差。
算法刚开始时候,大部分桶是0,稀疏格式存储连续0的个数,不是每个0存储,减少空间。后来变成紧凑格式,每个都存储。
当数据少时候,估算误差很大,用另一个近似值
java模拟算法
扩展
- 探索HyperLogLog算法,https://www.jianshu.com/p/55defda6dcd2
- 算法仿真,http://content.research.neustar.biz/blog/hll.html
- redis源码,