首頁 > 軟體

springboot+redis實現微博熱搜排行榜的範例程式碼

2022-05-18 16:00:29

技術模擬思路:

採用26個英文字母來實現排行,隨機為每個字母生成一個亂數作為score

為了更好的體驗,先做幾件事:

  • 先初始化1個月的歷史資料
  • 定時5秒鐘,模擬微博的熱度重新整理(例如模擬點贊 收藏 評論的熱度值更新)
  • 定時1小時合併統計 天、周、月的排行榜。

步驟1:先初始化1個月的歷史資料

@Service
@Slf4j
public class InitService {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 先初始化1個月的歷史資料
     */
    public void init30day(){
        //計算當前的小時key
        long hour=System.currentTimeMillis()/(1000*60*60);
        //初始化近30天,每天24個key
        for(int i=1;i<24*30;i++){
            //倒推過去30天
            String  key=Constants.HOUR_KEY+(hour-i);
            this.initMember(key);
            System.out.println(key);
        }
    }

    /**
     *初始化某個小時的key
     */
    public void initMember(String key) {
        Random rand = new Random();
        //採用26個英文字母來實現排行,隨機為每個字母生成一個亂數作為score
        for(int i = 1;i<=26;i++){
            this.redisTemplate.opsForZSet().add(key,String.valueOf((char)(96+i)),rand.nextInt(10));
        }
    }

}

步驟2:定時重新整理資料

@Service
@Slf4j
public class TaskService {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     *2. 定時5秒鐘,模擬微博的熱度重新整理(例如模擬點贊 收藏 評論的熱度值更新)
     * 3. 定時1小時合併統計 天、周、月的排行榜。
     */
    @PostConstruct
    public void init(){
        log.info("啟動初始化 ..........");
//        2. 定時5秒鐘,模擬微博的熱度重新整理(例如模擬點贊 收藏 評論的熱度值更新)
        new Thread(()->this.refreshDataHour()).start();
//        3. 定時1小時合併統計 天、周、月的排行榜。
        new Thread(()->this.refreshData()).start();
    }

    /**
     *採用26個英文字母來實現排行,隨機為每個字母生成一個亂數作為score
     */
    public void refreshHour(){
        //計算當前的小時key
        long hour=System.currentTimeMillis()/(1000*60*60);
        //為26個英文字母來實現排行,隨機為每個字母生成一個亂數作為score
        Random rand = new Random();
        for(int i = 1;i<=26;i++){
            //redis的ZINCRBY 新增這個積分值
            this.redisTemplate.opsForZSet().incrementScore(Constants.HOUR_KEY+hour,String.valueOf((char)(96+i)),rand.nextInt(10));
        }
    }

    /**
     *重新整理當天的統計資料
     */
    public void refreshDay(){
        long hour=System.currentTimeMillis()/(1000*60*60);
        List<String> otherKeys=new ArrayList<>();
        //算出近24小時內的key
        for(int i=1;i<23;i++){
            String  key=Constants.HOUR_KEY+(hour-i);
            otherKeys.add(key);
        }
        //把當前的時間key,並且把後推23個小時,共計近24小時,求出並集存入Constants.DAY_KEY中
        //redis ZUNIONSTORE 求並集
        this.redisTemplate.opsForZSet().unionAndStore(Constants.HOUR_KEY+hour,otherKeys,Constants.DAY_KEY);

        //設定當天的key 40天過期,不然歷史資料浪費記憶體
        for(int i=0;i<24;i++){
            String  key=Constants.HOUR_KEY+(hour-i);
            this.redisTemplate.expire(key,40, TimeUnit.DAYS);
        }
        log.info("天重新整理完成..........");
    }
    /**
     *重新整理7天的統計資料
     */
    public void refreshWeek(){
        long hour=System.currentTimeMillis()/(1000*60*60);
        List<String> otherKeys=new ArrayList<>();
        //算出近7天內的key
        for(int i=1;i<24*7-1;i++){
            String  key=Constants.HOUR_KEY+(hour-i);
            otherKeys.add(key);
        }
        //把當前的時間key,並且把後推24*7-1個小時,共計近24*7小時,求出並集存入Constants.WEEK_KEY中
        this.redisTemplate.opsForZSet().unionAndStore(Constants.HOUR_KEY+hour,otherKeys,Constants.WEEK_KEY);

        log.info("周重新整理完成..........");
    }

    /**
     *重新整理30天的統計資料
     */
    public void refreshMonth(){
        long hour=System.currentTimeMillis()/(1000*60*60);
        List<String> otherKeys=new ArrayList<>();
        //算出近30天內的key
        for(int i=1;i<24*30-1;i++){
            String  key=Constants.HOUR_KEY+(hour-i);
            otherKeys.add(key);
        }
        //把當前的時間key,並且把後推24*30個小時,共計近24*30小時,求出並集存入Constants.MONTH_KEY中
        this.redisTemplate.opsForZSet().unionAndStore(Constants.HOUR_KEY+hour,otherKeys,Constants.MONTH_KEY);
        log.info("月重新整理完成..........");
    }

    /**
     *定時1小時合併統計 天、周、月的排行榜。
     */
    public void refreshData(){
        while (true){
            //重新整理當天的統計資料
            this.refreshDay();
//            重新整理7天的統計資料
            this.refreshWeek();
//            重新整理30天的統計資料
            this.refreshMonth();
            //TODO 在分散式系統中,建議用xxljob來實現定時
            try {
                Thread.sleep(1000*60*60);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     *定時5秒鐘,模擬微博的熱度重新整理(例如模擬點贊 收藏 評論的熱度值更新)
     */
    public void refreshDataHour(){
        while (true){
            this.refreshHour();
            //TODO 在分散式系統中,建議用xxljob來實現定時
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

步驟3:排行榜查詢介面

@RestController
@Slf4j
public class Controller {

    @Autowired
    private RedisTemplate redisTemplate;


    @GetMapping(value = "/getHour")
    public Set getHour() {
        long hour=System.currentTimeMillis()/(1000*60*60);
        //ZREVRANGE 返回有序集key中,指定區間內的成員,降序。
        Set<ZSetOperations.TypedTuple<Integer>> rang= this.redisTemplate.opsForZSet().reverseRangeWithScores(Constants.HOUR_KEY+hour,0,30);
        return rang;
    }
    @GetMapping(value = "/getDay")
    public Set getDay() {
        Set<ZSetOperations.TypedTuple<Integer>> rang= this.redisTemplate.opsForZSet().reverseRangeWithScores(Constants.DAY_KEY,0,30);
        return rang;
    }

    @GetMapping(value = "/getWeek")
    public Set getWeek() {
        Set<ZSetOperations.TypedTuple<Integer>> rang= this.redisTemplate.opsForZSet().reverseRangeWithScores(Constants.WEEK_KEY,0,30);
        return rang;
    }

    @GetMapping(value = "/getMonth")
    public Set getMonth() {
        Set<ZSetOperations.TypedTuple<Integer>> rang= this.redisTemplate.opsForZSet().reverseRangeWithScores(Constants.MONTH_KEY,0,30);
        return rang;
    }
}

到此這篇關於springboot+redis實現微博熱搜排行榜的範例程式碼的文章就介紹到這了,更多相關springboot redis微博熱搜排行榜內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com