美文网首页
使用redis实现排行榜

使用redis实现排行榜

作者: 张云飞Vir | 来源:发表于2022-09-26 19:02 被阅读0次

    写在前面

    排行榜在很多地方都能使用到,redis的zset可以很方便地用来实现排行榜功能。本文是一个示例。

    聊聊 zset

    ZSet 是有序集合,redis的有序集合与集合一样也是String类型元素的集合,不允许有重复的元素。 每一个元素都会关联一个double类型的分数,redis正是通过分数来为集合中的成员进行从小到大的排序。
    有序集合中的成员是唯一的,但是分数可以重复。

    集合是通过哈希表实现的,集合中的最大元素是2的32次方减1。Zset是有序且不重复的。
    注意:默认排序从小到大。对于一般分数从高到低排列的话,可考虑加上负号,比如 100 变成 -100.

    添加一个
    zadd money_rank 100 zyf
    
    为 zyf 这个元素的得分 加上 3
    zincrby money_rank 3 zyf
    
    去处前三名
    zrange money_rank 0 3
    
    列出全部,并显示分数(从低到高)
    zrange money_rank 0 -1 withscores
    
    列出全部,并显示分数(从高到低)
    zrevrange WARNING_COUNT_RANK 0 -1 withscores
    
    查看有多少人
    zcard money_rank
    
    查看 zyf 的排名次序
    zrank money_rank zyf
    
    查看 zyf 的排名次序 (倒序)
    zrevrank rank c++
    
    移除
    zrem money_rank zyf
    
    

    用 java 代码实现示例

    由于 redis 的zset 默认的事从低到高排序,这里使用的反转的排序
    用了这些方法:

    • 得分/数量变化:stringRedisTemplate.opsForZSet().add(...)
    • 获得排行榜:stringRedisTemplate.opsForZSet().reverseRangeWithScores(...)
    • 查询某个设备的得分:stringRedisTemplate.opsForZSet().reverseRank(...)

    触发 得分变化

        // 触发 一个设备的报警
        @PostMapping("/warning/{deviceId}/{num}")
        String warning(@PathVariable String deviceId, @PathVariable int num) {
            // zadd 方法:不存在则添加,存在则更新
            //Boolean add = stringRedisTemplate.opsForZSet().add(WARNING_COUNT_RANK, deviceId, num);
            // zincr 方法:不存在则从0+delta,存在则累加
            Double aDouble = stringRedisTemplate.opsForZSet().incrementScore(WARNING_COUNT_RANK, deviceId, num);
            return aDouble + "";
        }
    

    获得总排行榜

        /**
         * 获得总排行榜
         *
         * @param topN 前多少名
         * @return
         */
        @GetMapping("/top")
        List<DeviceRank> getTotalRank(@RequestParam(defaultValue = "10", required = false) Integer topN) {
            List<DeviceRank> lst = new ArrayList<>();
            Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet().reverseRangeWithScores(WARNING_COUNT_RANK, 0, topN - 1);
            typedTuples.forEach(p -> {
                String value = p.getValue();
                Double score = p.getScore();
                lst.add(new DeviceRank(value, score));
            });
            return lst;
        }
    

    获得某个设备的名次

        /**
         * 获得某个设备的名次
         *
         * @param deviceId 设备id
         * @return
         */
        @GetMapping("/myrank")
        String getDevicesRank(String deviceId) {
            Long rank = stringRedisTemplate.opsForZSet().reverseRank(WARNING_COUNT_RANK, deviceId);
            return String.format("你是第 %s 名", rank + 1);
        }
    

    相关文章

      网友评论

          本文标题:使用redis实现排行榜

          本文链接:https://www.haomeiwen.com/subject/gcfaortx.html