首頁  >  文章  >  資料庫  >  關於java基於redis有序集合實現排行榜

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

藏色散人
藏色散人轉載
2020-09-11 13:22:502037瀏覽

下面由Redis教學欄位介紹關於java基於java基於redis有序集合實現排行榜,希望對需要的朋友有幫助!

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

前言

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

基於redis實現排行榜

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

#1 .相關的redis知識

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

關於sort set

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

資料結構組成:

  • 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);
        }
    }</tbcommpany></object>

取得排名

    /**
     * 获得公司排行榜(前十)
     * @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基於redis有序集合實現排行榜的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:csdn.net。如有侵權,請聯絡admin@php.cn刪除