Redis案例:最热门排行

最热门排行

考虑redis的zset结构,创建一个top的 key, 子key为热点,score 为关注度。每次关注数增加时调用zincrby,增加score。需要获取时,调用zrevrange 获取top10的结果即可。如果觉得保存热点作为key代价高,就可以结合mysql,做一个索引映射吧。redis 保存归一化的值。mysql保存真实数据,需要获取的时候再去mysql检索就好。

1、实现接口

package com.strap.mydemo.redis;

import java.util.List;

/**
 * <p>热点排行版</p>
 *
 * @author strap
 */
public interface HotRanking {

    /**
     * 当前排行榜的唯一key
     */
    String getRankingNameKey();

    /**
     * 往排行榜添加记录,如果记录存在,就增加其分数,如果不存在则创建并使用score作为基础份,最后返回当前排行版内其分数值,
     */
    Double addTarget(String key, double score);

    /**
     * 按正序(倒序)获取排行版中的ID列表
     */
    List<String> getRankList(Integer pageSize, boolean desc);

    /**
     * 按正序(倒序)获取排行版中的某个ID的排位
     */
    Long getRank(String key, boolean desc);

    /**
     * 清空排行版
     */
    Boolean deleteRanking();
}

2、实现抽象类

package com.strap.mydemo.redis;

import cn.hutool.core.collection.CollectionUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p></p>
 *
 * @author strap
 */
public abstract class HotRankingAbstract implements HotRanking{

    @Resource
    protected RedisTemplate<String, Object> redisTemplate;

    public HotRankingAbstract() {
    }

    @Override
    public Double addTarget(String key, double score) {
        return redisTemplate.opsForZSet().incrementScore(getRankingNameKey(), key, score);
    }

    @Override
    public Boolean deleteRanking() {
       return redisTemplate.delete(getRankingNameKey());
    }

    /**
     * 倒序获取对应key排名
     */
    public Long getRank(String key) {
        return getRank(key, true);
    }

    /**
     * 按分数倒序获取值
     */
    public List<String> getRankList(Integer pageSize) {
        return getRankList(pageSize, true);
    }

    @Override
    public List<String> getRankList(Integer pageSize, boolean desc) {
        Set<ZSetOperations.TypedTuple<Object>> typedTuples = desc ?
                redisTemplate.opsForZSet().reverseRangeWithScores(getRankingNameKey(), 0, pageSize - 1)
                : redisTemplate.opsForZSet().rangeWithScores(getRankingNameKey(), 0, pageSize - 1);
        return CollectionUtil.isEmpty(typedTuples) ? Collections.emptyList() : typedTuples.stream().map(i -> String.valueOf(i.getValue())).collect(Collectors.toList());
    }

    @Override
    public Long getRank(String key, boolean desc) {
        Long rank = desc ? redisTemplate.opsForZSet().reverseRank(getRankingNameKey(), key)
                : redisTemplate.opsForZSet().rank(getRankingNameKey(), key);
        return rank == null ? -1L : rank + 1;
    }
}

3、实现子类

package com.strap.mydemo.redis;

import org.springframework.stereotype.Component;

/**
 * <p></p>
 *
 * @author strap
 */
@Component
public class BookHotRanking extends HotRankingAbstract{

    public BookHotRanking() {
    }

    @Override
    public String getRankingNameKey() {
        return "hot:ranking:book";
    }
}

4、测试

      for (int i = 0; i < 20; i++) {
          bookHotRanking.addTarget(RandomUtil.randomInt(5) + "", 1);
      }

      log.info(bookHotRanking.getRankList(5));
      log.info(bookHotRanking.getRankList(3, false));
      log.info(bookHotRanking.getRank("1", false));
      log.info(bookHotRanking.getRank("7"));
      bookHotRanking.deleteRanking();

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值