關于java基于redis有序集合實現排行榜

下面由redis教程欄目給大家介紹關于java基于redis有序集合實現排行榜,希望對需要的朋友有所幫助!

關于java基于redis有序集合實現排行榜

前言

排行榜作為互聯網應用中幾乎必不可少的一個元素,能勾起人類自身對比的欲望,某寶中的商品銷量排行,店鋪信譽排行等,實現排行榜的方式也有很多種,可以使用快速排序算法 + 實現Comparator接口實現按某項權重排序,現在很多公司都在使用redis這個nosql數據庫實現排行榜的功能

基于redis實現排行榜

現在要做的是對公司進行排行,排行的標準是用戶對公司的搜索次數,做一個前十公司的排行榜

1.相關的redis知識

與排行榜功能實現相關的redis數據結構是sort set(有序集合)

關于sort set

我們知道set是一種集合,集合有一個特點就是無重復元素,sort set除了無重復元素外,還有一個特點就是有序性。

立即學習Java免費學習筆記(深入)”;

數據結構組成:

  • key:sort set 的唯一標識
  • 權重:也叫分數(score)redis通過權重為集合中的元素進行升序排序(默認),權重可以重復
  • value:集合元素,元素不可重復
String(set key),double(權重),String(value)

sort set是通過哈希表實現的,所以添加,函數,查找的時間復雜度都是O(1),每個集合可以存儲40多億個元素

基本命令

向集合中添加一個或多個元素

ZADD "KEY" SCORE "VALUE" [ SCORE "VALUE"]

效果:

MyRedis:0>ZADD test 1 "one""1"MyRedis:0>zadd test 4 "four" 5 "five""2"

獲取集合的元素數量

ZCARD "key"

效果

MyRedis:0>ZCARD test"5"

獲取指定元素分數(權重)

ZSCORE "KEY" "VALUE"

效果

MyRedis:0>ZSCORE "test" "one""2"

指定集合的指定元素增加指定分數

ZINCRBY "key" score "value"

效果:

MyRedis:0>ZSCORE "test" "one""2"MyRedis:0>ZINCRBY "test" 1 "one""3"MyRedis:0>ZSCORE "test" "one" "3"

獲取指定范圍的元素(默認按照分數|權重的升序排列)

ZRANGE "key" 開始下標 結束下標

效果

MyRedis:0>ZRANGE "test" 0 1  1)  "two"  2)  "one"

完成這個需求大概需要這么多命令,接下來開始實現我們的這個需求

2.springboot + redis實現

導入redis依賴

        <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-data-redis</artifactId>         </dependency>

編寫工具類

    //=============================== sort set =================================      /**      * 添加指定元素到有序集合中      * @param key      * @param score      * @param value      * @return      */     public boolean sortSetAdd(String key,double score,String value){         try{             return redisTemplate.opsForZSet().add(key,value,score);         }catch (Exception e){             e.printStackTrace();             return false;         }     }      /**      * 有序集合中對指定成員的分數加上增量 increment      * @param key      * @param value      * @param i      * @return      */     public double sortSetZincrby(String key,String value,double i){         try {             //返回新增元素后的分數             return redisTemplate.opsForZSet().incrementScore(key, value, i);         }catch(Exception e){             e.printStackTrace();             return -1;         }     }      /**      * 獲得有序集合指定范圍元素 (從大到小)      * @param key      * @param start      * @param end      * @return      */     public Set sortSetRange(String key,int start,int end){         try {             return redisTemplate.opsForZSet().reverseRange(key, start, end);         }catch (Exception e){             e.printStackTrace();             return null;         }     }

業務實現:

關于java基于redis有序集合實現排行榜

因為排行榜對實時性要求比較高,個人認為沒必要進行持久化到數據庫

    /**      * 根據公司名找到指定公司      * @param companyName      * @return      */     @Override     public AjaxResult selectCompanyName(String companyName) {         Set<Object> set =  redisUtils.sGet("company");         for(Object i : set){             String json = JSONObject.toJSONString(i);             JSONObject jsonObject = JSONObject.parseObject(json);             if(jsonObject.getString("companyName").equals(companyName)){                 //搜索次數 + 1                 redisUtils.sortSetZincrby("companyRank",companyName,1);                 log.info("直接緩存中返回");                 return new AjaxResult().ok(jsonObject);             }         }         log.error("緩存中沒有,查數據庫");         TbCommpanyExample tbCommpanyExample = new TbCommpanyExample();         tbCommpanyExample.createCriteria().andCompanyNameEqualTo(companyName);         List<TbCommpany> list = tbCommpanyMapper.selectByExample(tbCommpanyExample);         if(list.size() != 0){             //放入緩存中             redisUtils.sSet("company",list.get(0));             //數據庫中存在             //搜索次數 + 1             redisUtils.sortSetZincrby("companyRank",companyName,1);             log.info("sql");             return new AjaxResult().ok(list.get(0));         }else{             return new AjaxResult().error("沒有找到該公司:"+companyName);         }     }

獲取排名

    /**      * 獲得公司排行榜(前十)      * @return      */     @Override     public AjaxResult getCompanyRank() {         Set set = redisUtils.sortSetRange("companyRank",0,9);         if(set.size() == 0){             return new AjaxResult().error("公司排行榜為空");         }         return new AjaxResult().ok(set);     }

3.測試與總結

關于java基于redis有序集合實現排行榜

postman測試:

關于java基于redis有序集合實現排行榜

還有一個問題就是相同分數的排行問題

如果我希望A是先到的排在相同分數但是后到的B前邊,這個問題該如何解決呢?

要解決這個問題,我們可以考慮在分數中加入時間戳,計算公式為:

帶時間戳的分數 = 實際分數*10000000000 + (9999999999 – timestamp)

這個帶時間的公司可以自己編寫,盡量縮減誤差

以上就是關于java基于

? 版權聲明
THE END
喜歡就支持一下吧
點贊15 分享