使用Redis统计网站的UV/DAU

这篇具有很好参考价值的文章主要介绍了使用Redis统计网站的UV/DAU。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

HyperLogLog/BitMap

统计UV、DAU需要用到Redis的高级数据类型

M

public class RedisKeyUtil {

    private static final String PREFIX_UV = "uv";
    private static final String PREFIX_DAU = "dau";

    // a single day's UV
    public static String getUVKey(String date){
        return PREFIX_UV + SPLIT + date;
    }

    // a series of days' UV
    public static String getUVKey(String startDate, String endDate){
        return PREFIX_UV + SPLIT + startDate + SPLIT + endDate;
    }

    // get the DAU of a single day
    public static String getDAUKey(String date){
        return PREFIX_DAU + SPLIT + date;
    }

    // get the DAU of a series of days
    public static String getDAUKey(String startDate, String endDate){
        return PREFIX_DAU + SPLIT + startDate + SPLIT + endDate;
    }
}

C

@Service
public class DataService {

    @Autowired
    private RedisTemplate redisTemplate;

    private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");

    // add the specified IP address to the UV
    public void recordUV(String ip){
        String redisKey = RedisKeyUtil.getUVKey(dateFormat.format(new Date()));
        redisTemplate.opsForHyperLogLog().add(redisKey, ip);
    }

    // query the specified range of days' UV
    public long calculateUV(Date start, Date end) {
        if(start == null || end == null){
            throw new IllegalArgumentException("start and end must not be null");
        }

        if(start.after(end)){
            throw new IllegalArgumentException("start date should be before end date");
        }

        // get all the keys of those days
        List<String> keyList = new ArrayList<>();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(start);
        while(!calendar.getTime().after(end)){
            String redisKey = RedisKeyUtil.getUVKey(dateFormat.format(calendar.getTime()));
            keyList.add(redisKey);

            // add calendar to 1
            calendar.add(Calendar.DATE, 1);
        }

        // merge all the UV of those days
        String redisKey = RedisKeyUtil.getUVKey(dateFormat.format(start), dateFormat.format(end));
        redisTemplate.opsForHyperLogLog().union(redisKey, keyList.toArray());

        // return the statistics result
        return redisTemplate.opsForHyperLogLog().size(redisKey);
    }

    // add the specified user to the DAU
    public void recordDAU(int userId){
        String redisKey = RedisKeyUtil.getDAUKey(dateFormat.format(new Date()));
        redisTemplate.opsForValue().setBit(redisKey, userId, true);
    }

    // query the specified range of days' DAV
    public long calculateDAU(Date start, Date end){
        if(start == null || end == null){
            throw new IllegalArgumentException("start and end must not be null");
        }

        if(start.after(end)){
            throw new IllegalArgumentException("start date should be before end date");
        }

        // get all the keys of those days
        List<byte[]> keyList = new ArrayList<>();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(start);
        while(!calendar.getTime().after(end)){
            String key = RedisKeyUtil.getDAUKey(dateFormat.format(calendar.getTime()));
            keyList.add(key.getBytes());

            // add calendar to 1
            calendar.add(Calendar.DATE, 1);
        }

        // or operation
        return (long) redisTemplate.execute(new RedisCallback() {
            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                String redisKey = RedisKeyUtil.getDAUKey(dateFormat.format(start), dateFormat.format(end));
                connection.stringCommands().bitOp(RedisStringCommands.BitOperation.OR,
                        redisKey.getBytes(), keyList.toArray(new byte[0][0]));
                return connection.stringCommands().bitCount(redisKey.getBytes());
            }
        });
    }
}

使用拦截器记录访问

@Component
public class DataInterceptor implements HandlerInterceptor{

    @Autowired
    private DataService dataService;

    @Autowired
    private HostHolder hostHolder;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // record into the UV
        String ip = request.getRemoteHost();
        dataService.recordUV(ip);

        // record into the DAU
        User user = hostHolder.getUser();
        if(user != null){
            dataService.recordDAU(user.getId());
        }

        return true;
    }
}

配置拦截器文章来源地址https://www.toymoban.com/news/detail-677034.html

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private DataInterceptor dataInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
               registry.addInterceptor(dataInterceptor)
                .excludePathPatterns("/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg");
    }
}

V

@Controller
public class DataController {

    @Autowired
    private DataService dataService;

    // the page of the statistics
    @RequestMapping(path = "/data", method = {RequestMethod.GET, RequestMethod.POST})
    public String getDataPage() {
        return "/site/admin/data";
    }

    // calculates the UV of the site
//    @PostMapping(path = "/data/uv")
    @RequestMapping(path = "/data/uv", method = {RequestMethod.GET/*, RequestMethod.POST*/})
    public String getUV(@DateTimeFormat(pattern = "yyyy-MM-dd") Date start,
                        @DateTimeFormat(pattern = "yyyy-MM-dd") Date end, Model model) {

        long uv = dataService.calculateUV(start, end);

        model.addAttribute("uvResult", uv);
        model.addAttribute("uvStartDate", start);
        model.addAttribute("uvEndDate", end);

        // `forward` means this function just disposal a half of the request,
        // and the rest of request need to be executed by other functions
        // post request still be post after forwarding
        return "forward:/data";
    }

    // calculates the DAU of the site
//    @PostMapping(path = "/data/dau")
    @RequestMapping(path = "/data/dau", method = {RequestMethod.GET/*, RequestMethod.POST*/})
    public String getDAU(@DateTimeFormat(pattern = "yyyy-MM-dd") Date start,
                        @DateTimeFormat(pattern = "yyyy-MM-dd") Date end, Model model) {
        long dau = dataService.calculateDAU(start, end);
        model.addAttribute("dauResult", dau);
        model.addAttribute("dauStartDate", start);
        model.addAttribute("dauEndDate", end);

        // `forward` means this function just disposal a half of the request,
        // and the rest of request need to be executed by other functions
        // post request still be post after forwarding
        return "forward:/data";
    }
}

到了这里,关于使用Redis统计网站的UV/DAU的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

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

    前言 Redis除了常见的五种数据类型之外,其实还有一些少见的数据结构,如Geo,HyperLogLog等。虽然它们少见,但是作用却不容小觑。本文将介绍HyperLogLog指令的语法和使用场景。 HyperLogLog介绍 HyperLogLog是Redis提供的一种不准确(标准误差为0.81%)的去重计数方案。 提到去重计数

    2024年01月21日
    浏览(39)
  • 【Redis应用】UV统计(四)

    🚗Redis应用学习·第四站~ 🚩本文已收录至专栏:Redis技术学习 首先我们要搞懂两个概念: UV :全称 Unique Visitor ,也叫 独立访客量 ,是指通过互联网访问、浏览这个网页的自然人。1天内同一个用户多次访问该网站,只记录1次。 PV :全称 Page View ,也叫 页面访问量或点击量

    2024年02月09日
    浏览(38)
  • Redis - 附近商铺、用户签到、UV统计

    底层都是基于地理坐标进行搜索,支持地理坐标的技术有很多,Redis就是其中之一 GEO 就是Geolocation的简写形式,代表 地理坐标 。 Redis 在3.2版本中加入了对GEO的支持, 允许存储地理坐标信息 ,帮助我们根据经纬度来检索数据。 常见的命令有 : GEOADD :添加一个地理空间信息,

    2024年02月13日
    浏览(29)
  • 大数据-玩转数据-Flink 网站UV统计

    在实际应用中,我们往往会关注,到底有多少不同的用户访问了网站,所以另外一个统计流量的重要指标是网站的独立访客数(Unique Visitor,UV)。 对于UserBehavior数据源来说,我们直接可以根据userId来区分不同的用户。 将userid放到SET集合里面,统计集合长度,便可以统计到网

    2024年02月11日
    浏览(37)
  • 基于埋点日志数据的网络流量统计 - PV、UV

    水善利万物而不争,处众人之所恶,故几于道💦 一、 网站总流量数统计 - PV   1. 需求分析   2. 代码实现    方式一    方式二    方式三:使用process算子实现    方式四:使用process算子实现 二、网站独立访客数统计 - UV   1. 需求分析   2. 代码实现   PV全称

    2024年02月14日
    浏览(27)
  • Keil uv5 MDK使用教程

      介绍一下单片机开发软件Keil的基本使用,以STM32f4固件库为基础创建工程模板   选择安装路径,其余默认即可,具体可以参考百度,安装包在附件 注意 :汉化会导致部分功能设置不显示   不同芯片加载包不一样,官网http://www.keil.com/dd2/pack下载 Keil.STM32F4xx_DFP.1.0.8,

    2024年02月06日
    浏览(39)
  • 如何使用Unfold3D对称翻转UV

    Unfold3D是一款专业的UV展开软件,它被广泛应用于数字内容创作和三维建模领域。在制作纹理贴图时,常常需要对UV进行翻转、对称处理,以便更好地利用纹理空间和提高贴图效果。本文将介绍如何使用Unfold3D对称翻转UV,以帮助您更好地处理UV纹理。 第一步:导入模型和设置

    2024年02月11日
    浏览(25)
  • Blender基础:UV编辑器、UV坐标、UV映射、UV展开

    目录 1 纹理 2 UV编辑器 3 UV坐标 4 UV映射 5 UV展开 6 纹理绘制 7 自动UV展开 8 手动UV展开 9 UV布局调整 10 练习,弯曲文字 1 纹理 纹理Texture,又叫贴图。 一般来说,物体的表面不是纯色的。由贴图来定义表面颜色。 2 UV编辑器 切换工作区UV Editing ,认识一下界面 1右侧3D视图: -编

    2024年02月09日
    浏览(33)
  • Unity中Shader的扭曲(同样使用了UV的扭曲)

    Unity中Shader的扭曲 注意:扭曲效果比较消耗手机性能 类似于透过 火焰 看火焰后的物体,火焰后的物体扭曲 类似于透过 水 看水中的物体,水中物体的扭曲

    2024年02月06日
    浏览(39)
  • Cocos creator(2d) 使用 shader + uv 实现单张图片衔接滚动效果

    在游戏中,当我们需要让背景图片无缝衔接无限滚动时(打飞机这种背景一直滚动,或者肉鸽游戏地图一直在走等等),通常的做法是 在游戏中放两个背景node,在update中控制这两张背景图片的移动,并让其收尾衔接即可。(具体代码忽略) 可是在肉鸽类游戏中,玩家的走向是全方

    2024年02月13日
    浏览(74)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包