Redis--HyperLogLog的指令语法与使用场景举例(UV统计)

文章目录

      • 前言
      • HyperLogLog介绍
      • HyperLogLog指令使用
      • 使用场景:UV统计

前言

  • Redis除了常见的五种数据类型之外,其实还有一些少见的数据结构,如Geo,HyperLogLog等。虽然它们少见,但是作用却不容小觑。本文将介绍HyperLogLog指令的语法和使用场景。

HyperLogLog介绍

  • HyperLogLog是Redis提供的一种不准确(标准误差为0.81%)的去重计数方案。
  • 提到去重计数,第一个想到的数据结构就是集合set,set集合可以保存数据,并用scard准确地返回集合中的数据条数,但是若数据量很大,那么使用set集合就需要相当大的存储空间,这显然不是我们想看到的结果,而对于某些统计其实并不需要特别精确的结果。
  • 对于这种情况,HyperLogLog就可以发挥大用,HyperLogLog的优势在于无论存储的数据量有多大,它都只需要12KB的存储空间(可以计算接近2^64个不同的基数)。当然它只能统计数据集的个数,而不直接存放元素,不能试图用它保存元素。另外HyperLogLog对数据集的统计也不是完全准确的,存在一定误差,可能比实际情况多或少。

HyperLogLog指令使用

  • 增加计数: pfadd key element [element...]

  • 查询计数: pfcount key

  • 将多个HyperLogLog合并到一个HyperLogLog中: pfmerge destkey sourcekey [sourcekey ...]

使用场景:UV统计

  • HyperLogLog最适合的使用场景就是做UV的统计了,简直量身定制一般。一个爆款页面的UV可能有几千万,使用HyperLogLog可以节约存储空间,并且UV的统计允许存在一定的误差。

    补充:

    • pv(page view,浏览量)
      • 页面的浏览次数,衡量网站用户访问的网页数量;
      • 用户每打开一个页面就记录1次,多次打开同一页面则浏览量累计。
    • uv(unique visitor,独立访客)
    • 1天内访问某站点的人数(以cookie为依据);
    • 1天内同一访客的多次访问只计为1个访客。
    • ip(独立ip)
    • 指1天内使用不同ip地址的用户访问网站的数量;
    • 同一IP不管访问了几个页面,独立IP数均为1。
  • 代码实现: 在代码中提供了三个方法,分别对应pfadd添加页面的UV,pfcount获取页面的UV统计结果和pfmerge合并指定页面UV。

    java 复制代码
    public class UVByHyperLogLog {
        public static void main(String[] args) {
            Jedis jedis = new Jedis("127.0.0.1");
            jedis.del(UV_PAGE_1);
            jedis.del(UV_PAGE_2);
            jedis.del(UV_PAGE_1_2);
            
            for (int i = 0; i < 10000; i++) {
                String userid = "userid:"+Math.random()*100000;
                addCount(UV_PAGE_1,userid,jedis);
            }
            System.out.println("页面一的UV:"+getCount(UV_PAGE_1,jedis));
    
            jedis.del(UV_PAGE_2);
            for (int i = 0; i < 5000; i++) {
                String userid = "userid:"+Math.random()*100000;
                addCount(UV_PAGE_2,userid,jedis);
            }
            System.out.println("页面二的UV:"+getCount(UV_PAGE_2,jedis));
    
            //页面一和页面二合并后的UV 合并与的UV不等于两个UV的相加,一样是不精确的
            mergeCount(UV_PAGE_1_2, new String[]{UV_PAGE_1, UV_PAGE_2},jedis);
            System.out.println("合并后两个页面的UV总数"+getCount(UV_PAGE_1_2,jedis));
        }
    
        private static final String UV_PAGE_1 = "UV_PAGE_1";
        private static final String UV_PAGE_2 = "UV_PAGE_2";
    
        private static final String UV_PAGE_1_2 = "UV_PAGE_1_2";
        /**
         * 向HyperLogLog添加数据
         * @param key UV_KEY
         * @param userId 用户Id
         * @param jedis
         */
        public static void addCount(String key, String userId,Jedis jedis){
            jedis.pfadd(key,userId);
        }
    
        /**
         * 返回统计的结果
         * @param key
         * @param jedis
         * @return
         */
        public static long getCount(String key,Jedis jedis){
            return jedis.pfcount(key);
        }
    
        /**
         * 将多个pf计数合并为一个pf计数
         * @param newKey 合并后的新HyperLogLog的key
         * @param keys  要合并的HyperLogLog的key
         * @param jedis
         * @return
         */
        public static void mergeCount(String newKey,String[] keys,Jedis jedis){
            jedis.pfmerge(newKey,keys);
        }
    }
  • 测试结果:在上述main方法中,第一个for循环,模拟10000个用户访问页面一,第二个for循环模拟5000个用户访问页面二,通过HyperLogLog进行UV统计,输出统计结果,最后合并两个页面的统计值,观察结果后发现,HyperLogLog统计后的结果与实际结果存在误差,但是在数据量很大的情况下,这点误差误伤大雅。:

相关推荐
raoxiaoya38 分钟前
同时安装多个版本的golang
开发语言·后端·golang
rainFFrain2 小时前
(MySQL)库的操作
数据库·mysql
考虑考虑2 小时前
go使用gorilla/websocket实现websocket
后端·程序员·go
李少兄2 小时前
解决Spring Boot多模块自动配置失效问题
java·spring boot·后端
八股文领域大手子3 小时前
深入理解缓存淘汰策略:LRU 与 LFU 算法详解及 Java 实现
java·数据库·算法·缓存·mybatis·哈希算法
noravinsc3 小时前
django admin 中更新表数据 之后再将数据返回管理界面
数据库·django·sqlite
Piper蛋窝3 小时前
Go 1.19 相比 Go 1.18 有哪些值得注意的改动?
后端
码农BookSea3 小时前
不用Mockito写单元测试?你可能在浪费一半时间
后端·单元测试
codingandsleeping4 小时前
Express入门
javascript·后端·node.js
ss2735 小时前
基于Springboot + vue + 爬虫实现的高考志愿智能推荐系统
spring boot·后端·高考