Redis之HyperLogLog类型解读

目录

基本介绍

基本命令

pfadd

pfcount

pgmerge

统计访客应用场景 

什么是UV、PV、DAU、MAU

场景说明

java代码示例


基本介绍

HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。

在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。

但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。

基数是什么?

比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素)为5。 基数估计就是在误差可接受的范围内,快速计算基数。

去重复统计功能的基数估计算法-就是HyperLogLog(用于统计一个集合中不重复的元素个数,就是对集合去重复后剩余元素的计算) ,需要注意存在误差(准确率来换取空间,误差仅仅只是0.81%左右)

全集i={1,2,3,4,5,6,7,8,8,9,9,5}
去掉重复的内容
基数={1,2,3,4,5,6,7,8,9}

基本命令

序号 命令及描述
1 PFADD key element [element ...] 添加指定元素到 HyperLogLog 中。
2 PFCOUNT key [key ...] 返回给定 HyperLogLog 的基数估算值。
3 PFMERGE destkey sourcekey [sourcekey ...] 将多个 HyperLogLog 合并为一个 HyperLogLog

pfadd

Pfadd 命令将所有元素参数添加到 HyperLogLog 数据结构中。

redis> PFADD mykey a b c d e f g h i j
(integer) 1

redis> PFCOUNT mykey
(integer) 10

返回值:整型,如果至少有个元素被添加返回 1,否则返回 0。 

pfcount

Pfcount 命令返回给定 HyperLogLog 的基数估算值

语法:PFCOUNT key [key ...] 

redis> PFADD hll foo bar zap
(integer) 1

redis> PFADD hll zap zap zap
(integer) 0

redis> PFADD hll foo bar
(integer) 0

redis> PFCOUNT hll
(integer) 3

redis> PFADD some-other-hll 1 2 3
(integer) 1

redis> PFCOUNT hll some-other-hll
(integer) 6

返回值:整数,返回给定 HyperLogLog 的基数值,如果多个 HyperLogLog 则返回基数估值之和。

pgmerge

Pgmerge 命令将多个 HyperLogLog 合并为一个 HyperLogLog ,合并后的 HyperLogLog 的基数估算值是通过对所有 给定 HyperLogLog 进行并集计算得出的。

redis> PFADD hll1 foo bar zap a
(integer) 1

redis> PFADD hll2 a b c foo
(integer) 1

redis> PFMERGE hll3 hll1 hll2
OK

redis> PFCOUNT hll3
(integer) 6

返回值:返回 OK。

统计访客应用场景 

什么是UV、PV、DAU、MAU


①. UV:Unique Visitor,独立访客,一般理解为客户端IP(需要去重考虑)

②. PV:Page View,页面浏览量(不用去重)

③. DAU:日活跃用户量(登录或者使用了某个产品的用户数(去重复登录的用户))

④. MAU:MonthIy Active User,月活跃用户量 

场景说明

淘宝、天猫首页的UV,平均每天是1~1.5个亿左右

每天存1.5个亿的IP,访问者来了后先去查是否存在,不存在加入

一个用户一天内的多次访问只能算作一次

java代码示例

@Service
@Slf4j
public class HyperLogLogService {
    @Resource
    private RedisTemplate redisTemplate;

    /**
     * 模拟有用户来点击首页,每个用户就是不同的ip,不重复记录,重复不记录
     */
    @PostConstruct
    public void init() {
        log.info("------模拟后台有用户点击,每个用户ip不同");
        //自己启动线程模拟,实际上产不是线程
        new Thread(() -> {
            String ip = null;
            for (int i = 1; i <=200; i++) {
                Random random = new Random();
                ip = random.nextInt(255)+"."+random.nextInt(255)+"."+random.nextInt(255)+"."+random.nextInt(255);

                Long hll = redisTemplate.opsForHyperLogLog().add("hll", ip);
                log.info("ip={},该ip访问过的次数={}",ip,hll);
                //暂停3秒钟线程
                try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
            }
        },"t1").start();
    }
}
@RestController
@Slf4j
public class HyperLogLogController {

    @Resource
    private RedisTemplate redisTemplate;

    @ApiOperation("获得ip去重复后的首页访问量,总数统计")
    @RequestMapping(value = "/uv",method = RequestMethod.GET)
    public long uv() {
        //pfcount
        return redisTemplate.opsForHyperLogLog().size("hll");
    }
}

 通过牺牲准确率来换取空间,对于不要求绝对准确率的场景下可以使用,因为概率算法不直接存储数据本身 通过一定的概率统计方法预估基数值,同时保证误差在一定范围内,由于又不储存数据故此可以大大节约内存 HyperLogLog就是一种概率算法的实现

你可能感兴趣的:(redis7,redis,数据库,缓存,java,spring,boot)