Redis结合业务逻辑实现排行榜

前言

大家好,我又回来了。已经好久没有写博客了,今天要写的排行榜的需求:排名前50,然后标记自己的位置,如果超过就补到后面去。

其实实现很简单,就是redis zset数据结构实现。主要是自己一些思考。

实现

前num名次(倒序)

public List<ZSetOperations.TypedTuple> rangeTopLeaderboard(Long activityId, Integer num) {
        if (num < 0) {
            return Collections.emptyList();
        }
        Set<ZSetOperations.TypedTuple<String>> set = stringRedisTemplate.opsForZSet().reverseRangeWithScores(TwinkleCacheKey.getActivityLeaderboardAppidKey(activityId), 0, num);
        return new ArrayList<>(set);
    }

正序就是把reverse去掉。

加分数

Double incrementScore(K key, V value, double delta);

初始化

Boolean add(K key, V value, double score);

个人总结

附加信息

  我们的需求里面是有包含头像,个人信息什么的。如果说这些数据是不会变的,其实是可以序列化到 V value里面,可惜他们会变。

so 我只能单独再把这些冗余的信息放到缓存再封装返回给前端咯~

缓存问题

  同事考虑到用户频繁刷新会导致性能问题,决定缓存一哈~那么问题来了,我只能缓存前面固定的例如50条+自己的数据在排行榜的名次。5分钟重新刷新,其实刷的只是前50条,西西······

更正:上面这么做的有坑的,比如我前50条缓存了,我排名第一,然后我实时排名第二,如果说要标出自己的位置就出现bug了。

删除问题

  考虑到内存问题,可能也是有点杞人忧天吧。活动结束后一段时间会删除这个排行榜,不要再去占位置了,哈哈。

排序问题

  由于我们的需求是这样的,要不就并列名次,这个有点难,因为redis排序出来的哪有并列的,要不就按照用户先达到的特定数量的时间进行排序。

  我们使用第二种方法来实现需求。经过我和同事的激烈讨论之后得出结论:网上大多是在key或者score上加上时间戳,那就这样试下。

  由于这个key我们是不能变的,那么就改造score!

  由于redis zset返回的是double类型,考虑到精度,so加上时间戳(太长了,我们把前1位和后3位截取掉,前一位基本不会变,后3位代表秒)然后再跟真正的score拼接起来,格式:score.截取之后的时间戳

public static Double getScore(Double score) {
        long currentTime = System.currentTimeMillis();
        String time = String.valueOf(currentTime);
        //截取后3位
        time = time.substring(0, time.length() - 3);
        time = time.substring(1);
        //时间越早达到,排在越前
        time = String.valueOf(999999999L - Long.valueOf(time));
        String scoreValue = String.valueOf(score.intValue());
        return Double.valueOf(scoreValue + "." + time);
    }

  这里就使用不了zset的自增了,只能每次add去更新值。因为score是不断变化的。
在这里插入图片描述

测试demo

template.opsForZSet().add("dajitui","小红",5);
        template.opsForZSet().add("dajitui","小名",7);
        template.opsForZSet().add("dajitui","小白",2);
        template.opsForZSet().add("dajitui","小黑",8);
        template.opsForZSet().add("dajitui","小积",9);
        System.out.println(template.opsForZSet().reverseRank("dajitui","123"));
        System.out.println(template.opsForZSet().range("dajitui",0,5));
        System.out.println(template.opsForZSet().score("dajitui","小白"));
        Set<ZSetOperations.TypedTuple<String>> set=template.opsForZSet().reverseRangeWithScores("dajitui",0,5);
        for (ZSetOperations.TypedTuple<String> typedTuple : set) {
            System.out.println(typedTuple.getValue() + " " + typedTuple.getScore());
        }
        System.out.println("--------------------");
        template.opsForZSet().incrementScore("dajitui","小白",5);
        //System.out.println(template.opsForZSet().range("dajitui",0,5));
        Set<ZSetOperations.TypedTuple<String>> set1=template.opsForZSet().reverseRangeWithScores("dajitui",0,5);
        for (ZSetOperations.TypedTuple<String> typedTuple : set1) {
            System.out.println(typedTuple.getValue() + " " + typedTuple.getScore());
        }
        template.delete("dajitui");

基本够用了,that all,bye~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值