HyperLogLog命令是redis在2.8版本中加入的,Redis中HyperLogLog是用来做基数统计的。
HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的,因此每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 264 个不同元素的基数。但是HyperLogLog也存在缺点,就是它是估计基数的算法,所以会有一定误差0.81%,而且无法获取具体的元素值。因此应用在对准确性不是很重要的场景,例如:QQ同时在线人数,网站IP访问数量等等。
详情可以参考:https://chenjiehua.me/database/hyperloglog-bigdata.html
和https://blog.csdn.net/firenet1/article/details/77247649
顺便附上本地测试的小例子:
package com.redis.hyperLoglog;
import com.redis.util.RedisUtil;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;
/** * HyperLoglog * 基数计数(cardinality counting)通常用来统计一个集合中不重复的元素个数,例如统计某个网站的UV, * 或者用户搜索网站的关键词数量。数据分析、网络监控及数据库优化等领域都会涉及到基数计数的需求。 * 要实现基数计数,最简单的做法是记录集合中所有不重复的元素集合Su,当新来一个元素xi,若Su中不包含元素xi,则将xi * 加入Su,否则不加入,计数值就是Su的元素数量。这种做法存在两个问题: * 1.当统计的数据量变大时,相应的存储内存也会线性增长; * 2.当集合Su变大,判断其是否包含新加入元素xi的成本变大 * 大数据量背景下,要实现基数计数,首先需要确定存储统计数据的方案,以及如何根据存储的数据计算基数值; * 另外还有一些场景下需要融合多个独立统计的基数值,例如对一个网站分别统计了三天的UV, * 现在需要知道这三天的UV总量是多少,怎么融合多个统计值。 * */
public class HyperLoglogTest {
/** * 数据结构为HyperLoglog的数据存储 */
@Test
public void pfadd(){
Jedis jedis = RedisUtil.getJedis();
Long log1 = jedis.pfadd("log1", "1", "2", "3", "4");
System.out.println("返回值:"+log1);
Long log2 = jedis.pfadd("log2", "5", "6", "7", "7", "7");
System.out.println("返回值:"+log2);
Long log3 = jedis.pfadd("log3", "7","8");
System.out.println("返回值:"+log3);
}
/** * 数据结构为HyperLoglog的数据长度(基数) */
@Test
public void pfcount(){
Jedis jedis = RedisUtil.getJedis();
long log1 = jedis.pfcount("log1");
System.out.println("返回值:"+log1);
long log2 = jedis.pfcount("log2");
System.out.println("返回值:"+log2);
long log3 = jedis.pfcount("log3");
System.out.println("返回值:"+log3);
}
/** * 将多个HyperLoglog合并,合并到log1中,log2和log3为原始值。 * 从后台查看log1会发现log1占用的空间会明显的增大 */
@Test
public void pfmerge(){
Jedis jedis = RedisUtil.getJedis();
String pfmerge = jedis.pfmerge("log1", "log2","log3");
System.out.println("返回值:pfmerge:"+pfmerge);
System.out.println("================================");
long log1 = jedis.pfcount("log1");
System.out.println("返回值:"+log1);
long log2 = jedis.pfcount("log2");
System.out.println("返回值:"+log2);
long log3 = jedis.pfcount("log3");
System.out.println("返回值:"+log3);
}
}