使用redis的zset实现排行榜

1.使用场景

现在公司有个项目,类似于今日头条,需要实现对应分类阅读排行榜的功能。

每一篇文章所属于一个分类,当用户阅读该文章时,阅读次数+1,排行榜实时变化。

2.redis的ZSet数据结构

zset为有序集合。就是在set的基础上,添加了一个score值。zset的每一个成员都有一个分数与之对应,并且分数可以重复。score就相当于权重,可以根据score值进行排序展示。

项目中使用了SpringBoot整合的redisTemplate

常用方法如下:

  • Boolean add(K key, V value, double score):新增一个有序集合,存在的话为false,不存在的话为true

  • Long add(K key, Set<TypedTuple<V>> tuples):新增一个有序集合

  • Long remove(K key, Object... values):从有序集合中移除一个或者多个元素

  • Double incrementScore(K key, V value, double delta):增加元素的score值,并返回增加后的值

  • Set<V> range(K key, long start, long end):通过索引区间返回有序集合成指定区间内的成员,其中有序集成员按分数值递增(从小到大)顺序排列

  • Set<TypedTuple<V>> rangeWithScores(K key, long start, long end):通过索引区间返回有序集合成指定区间内的成员对象,其中有序集成员按分数值递增(从小到大)顺序排列

  • Set<V> rangeByScore(K key, double min, double max):通过分数返回有序集合指定区间内的成员,其中有序集成员按分数值递增(从小到大)顺序排列

  • Set<V> reverseRange(K key, long start, long end):通过索引区间返回有序集合成指定区间内的成员,其中有序集成员按分数值递减(从大到小)顺序排列

  • Double score(K key, Object o):获取指定成员的score值

3.代码实例

(1)项目中的缓存常量类

CacheConstant.java

    /**
     * 分类研报购买次数
     */
    public static final String REPORT_CATEGORY_BUY_COUNT = "report_report_category_buy_count:";

(2)CacheService.java

    @Autowired
    private RedisTemplate<String, Object> template;
​
    /**
     * 增加研报分类阅读次数(查看文章详情接口时调用)
     *
     * @param categoryId
     */
    public void incrReportCategoryReadCount(Long categoryId) {
        template.opsForZSet().incrementScore(CacheConstant.REPORT_CATEGORY_READ_COUNT, categoryId, 1);
    }
​
    /**
     * 获取研报分类阅读排行榜
     */
    public Set<Object> getReportCategoryReadCountRank() {
        if (template.hasKey(CacheConstant.REPORT_CATEGORY_READ_COUNT)) {
            //0,-1的参数代表查询该key下的所有value
            return template.opsForZSet().reverseRange(CacheConstant.REPORT_CATEGORY_READ_COUNT, 0, -1);
        } else {
            return new HashSet<>();
        }
    }
​
​
    /**
     * 获取研报分类阅读排行榜具体分类次数
     */
    public Double getReportCategoryBuyCount(Object o) {
        return template.opsForZSet().score(CacheConstant.REPORT_CATEGORY_BUY_COUNT, o);
    }
  • 这里我们将分类在数据库中的主键id存进去,以便按顺序查出来之后去数据库中查询对应的分类名。

  • score值就是该文章的阅读次数,可以直接调用接口获取

4.Rank.java

    public static class Rank implements Serializable {
        private Long id;
        private String name;
        private Integer times;
    }

5.StatisticService.java

    @Autowired
    private CacheService cacheService;
​
    public StatisticsPlatformResponse platform() {        
        //查询一级分类下的研报阅读排行
        List<Rank> readRank = new ArrayList<>();
        //一次性查询出所有一级分类,然后和分类排行榜的对应id去匹配
        List<ReportCategory> oneCategoryList = reportCategoryService.findAllOneCategory();
​
        Set<Object> readCountRank = cacheService.getReportCategoryReadCountRank();
        if (readCountRank != null) {
            for (Object o : readCountRank) {
                Rank singReadRank = getRank(oneCategoryList, (Number) o);
                singReadRank.setTimes(cacheService.getReportCategoryReadCount(o).intValue());
                readRank.add(singReadRank);
            }
        }
       return readRank;
   }
​
    private Rank getRank(List<ReportCategory> oneCategoryList, Number o) {
        Rank rank = new Rank();
        rank.setId(o.longValue());
        rank.setName(getCategoryName(o.longValue(), oneCategoryList));
        return rank;
    }

    /**
     * 获取分类名
     *
     * @param categoryId
     * @param list
     * @return
     */
    private String getCategoryName(Long categoryId, List<ReportCategory> list) {
        for (ReportCategory category : list) {
            if (category.getId().equals(categoryId)) {
                return category.getName();
            }
        }
        return null;
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值