成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Redis Zset詳解:排行榜絕佳選擇

開發 前端
通過本文的介紹,你學會了如何利用Spring Boot和Redis的ZSET數據結構實現熱門搜索功能,并深入了解了熱搜詞匯的實現細節。

最近我們發布了一款新的app,其中包含一個搜索功能。在搜索時,會給用戶展示四個熱門搜索詞匯。我們利用 Redis 的有序集合(zset)實現了這一功能。由于應用程序剛剛上線并且尚未大力推廣,所以熱門搜索詞匯顯示的是我們隨手測試詞匯,如測試、test、111等。這會給人一種不夠專業的印象。為了提升產品形象,我們計劃通過后臺刪除這些測試的詞匯,使熱門搜索詞匯更加貼近實際使用情況。今天,我將與大家分享在 Redis 命令行中操作有序集合(zset)的命令,以及我們實現熱門搜索詞匯功能的思路。

Redis ZSET 詳解

Redis 中的 ZSET(有序集合)是一種有序的數據結構,它類似于 SET(集合),但每個成員都關聯著一個分數(score),通過分數來進行排序。這使得 ZSET 既可以像 SET 一樣快速查找成員,又可以按照分數從小到大或從大到小進行排序。

ZSET 的特點包括:

  • 有序性:成員按照分數的順序排列,可以進行范圍查詢和排名操作。
  • 唯一性:每個成員都是唯一的,但不同成員可以有相同的分數。
  • 快速查找:和 SET 類似,ZSET 也可以在 O(1) 的時間復雜度內查找單個成員。
  • 分數(score)更新:可以對成員的分數進行增加或減少操作,同時保持排序。

ZSET 的底層實現會根據實際的情況選擇ziplist(壓縮列表)/listpack(緊湊列表)(redis7.0已經將 listpack 完整替代 ziplis) 或者skiplist(跳躍表),Redis 會根據實際情況動態地在這兩種底層結構之間切換,使得其在內存和性能之間平衡。這是由兩個配置參數:zset-max-ziplist-entries 和 zset-max-ziplist-value控制的,其默認值為128和64。當 Zset 存儲的元素數量超過zset-max-ziplist-entries的值或者最長元素的長度超過 zset-max-ziplist-value的值的時候Redis 會將底層結構從壓縮列表/緊湊列表轉換為跳躍表。壓縮列表/緊湊列表占用的內存比較少,但是修改數據時可能會對整個列表進行重寫,性能較低; 跳躍表的查找和修改數據的性能較高,但是占用的內存也較多。

我們在redis 命令行中可以通過以下命令查看 zset的配置參數:

config get zset*

圖片圖片

Redis ZSET 使用場景

  • 排行榜

Redis 的zset是設計實時排行的絕佳選擇,我們可以使用它來完成各種排行榜、熱門詞匯等場景的實現。我們app的熱搜詞匯也是通過zset實現的,本文中也將介紹熱搜詞匯的實現方式。

  • 延時隊列

我們可以將時間戳設置為zset的score,延時處理的任務作為元素,定期或者循環掃描zset來處理到達時間的任務。

  • 滑動窗口限流

我們可以將接口地址設置為zset的key,時間戳設置為zset的score,使用uuid作為元素,那么我們可以通過zset獲取到 score固定窗口范圍的時間內的請求數來達到限流的目的。

REDISSON 操作ZSET數據

代碼如下:

package cn.xj.xjdoc.redis.zset;


import jakarta.annotation.Resource;
import org.redisson.api.RScoredSortedSet;
import org.redisson.api.RedissonClient;
import org.redisson.client.protocol.ScoredEntry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.Collection;

@Service
public class ZSETService {

    private static final Logger log = LoggerFactory.getLogger(ZSETService.class);
    @Resource
    private RedissonClient redissonClient;

    public void operation(){

        String zsetKey = "xjzset";

        RScoredSortedSet<String> zset = redissonClient.getScoredSortedSet(zsetKey);
        //添加元素
        zset.add(1.0, "修己xj1");
        zset.add(2.0, "修己xj2");
        zset.add(3.0, "修己xj3");
        zset.add(4.0, "修己xj4");
        // 獲取ZSET中指定成員的分數
        Double score = zset.getScore("修己xj2");
        log.info("1、獲取ZSET中指定成員的分數:{}",score);

        //獲取ZSET中指定成員的排名(分數從小到大排序)
        Integer rank = zset.rank("修己xj3");
        log.info("2、獲取ZSET中指定成員的排名(分數從小到大排序):{}",rank);

        //獲取ZSET中指定成員的排名(分數從大到小排序)
        Integer reverseRank = zset.revRank("修己xj4");
        log.info("3、獲取ZSET中指定成員的排名(分數從大到小排序):{}",reverseRank);

        // 獲取ZSET中指定排名范圍內的成員(分數從小到大排序)
        Collection<String> membersInRange = zset.valueRange(0, 1);
        membersInRange.forEach(o->log.info("4、獲取ZSET中指定排名范圍內的成員(分數從小到大排序):{}",o));

        // 獲取ZSET中指定排名范圍內的成員(分數從大到小排序)
        Collection<String> membersInRangeRever = zset.valueRangeReversed(0, 1);
        membersInRangeRever.forEach(o->log.info("5、獲取ZSET中指定排名范圍內的成員(分數從大到小排序):{}",o));

        //獲取ZSET中指定分數范圍內的成員(分數從小到大排序)
        Collection<String> membersInScoreRange = zset.valueRange(2.0, true, 3.0, true);
        membersInScoreRange.forEach(o->log.info("6、獲取ZSET中指定分數范圍內的成員(分數從小到大排序):{}",o));

        //獲取ZSET中指定分數范圍內的成員(分數從大到小排序)
        Collection<String> membersInScoreRever = zset.valueRangeReversed(2.0, true, 3.0, true);
        membersInScoreRever.forEach(o->log.info("7、獲取ZSET中指定分數范圍內的成員(分數從大到小排序):{}",o));

        //獲取ZSET中指定排名范圍內的成員及其分數
        Collection<ScoredEntry<String>> membersWithScoresInRange = zset.entryRange(0, 1);
        membersWithScoresInRange.forEach(o->log.info("8、獲取ZSET中指定排名范圍內的成員及其分數,成員:{},分數",o.getValue(),o.getScore()));

        //獲取ZSET中指定分數范圍內的成員及其分數
        Collection<ScoredEntry<String>> membersWithScoresInScoreRange = zset.entryRange(3.0, true, 4.0, true);
        membersWithScoresInScoreRange.forEach(o->log.info("9、獲取ZSET中指定分數范圍內的成員及其分數,成員:{},分數",o.getValue(),o.getScore()));

        //

        Double newScore = zset.addScore("修己xj4", 1);
        log.info("10、增加1之后指定成員的分數:{}",newScore);

        //刪除ZSET 中的指定成員
        Boolean removedFlag = zset.remove("修己xj3");
        log.info("11、刪除ZSET 中的指定成員:{}",removedFlag);

        //刪除指定排名范圍內的成員
        Integer removedByRangeCount = zset.removeRangeByRank(0, 1);
        log.info("12、刪除指定排名范圍內的成員數量:{}",removedByRangeCount);

        //刪除指定分數范圍內的成員
        Integer removedByScoreCount = zset.removeRangeByScore(3.0, true, 4.0, true);
        log.info("13、刪除指定分數范圍內的成員數量:{}",removedByScoreCount);
    }

}

執行結果如下:

1、獲取ZSET中指定成員的分數:2.0
2、獲取ZSET中指定成員的排名(分數從小到大排序):2
3、獲取ZSET中指定成員的排名(分數從大到小排序):0
4、獲取ZSET中指定排名范圍內的成員(分數從小到大排序):修己xj1
4、獲取ZSET中指定排名范圍內的成員(分數從小到大排序):修己xj2
5、獲取ZSET中指定排名范圍內的成員(分數從大到小排序):修己xj4
5、獲取ZSET中指定排名范圍內的成員(分數從大到小排序):修己xj3
6、獲取ZSET中指定分數范圍內的成員(分數從小到大排序):修己xj2
6、獲取ZSET中指定分數范圍內的成員(分數從小到大排序):修己xj3
7、獲取ZSET中指定分數范圍內的成員(分數從大到小排序):修己xj3
7、獲取ZSET中指定分數范圍內的成員(分數從大到小排序):修己xj2
8、獲取ZSET中指定排名范圍內的成員及其分數,成員:修己xj1,分數
8、獲取ZSET中指定排名范圍內的成員及其分數,成員:修己xj2,分數
9、獲取ZSET中指定分數范圍內的成員及其分數,成員:修己xj3,分數
9、獲取ZSET中指定分數范圍內的成員及其分數,成員:修己xj4,分數
10、增加1之后指定成員的分數:5.0
11、刪除ZSET 中的指定成員:true
12、刪除指定排名范圍內的成員數量:2
13、刪除指定分數范圍內的成員數量:0

命令行操作ZSET數據

  • zadd 添加成員
zadd xjzset 1 "修己xj1" 2 "修己xj2" 3 "修己xj3" 4 "修己xj4"
  • zscore 獲取指定成員的分數
zscore xjzset '修己xj2'
  • zrank 獲取指定成員的排名(分數從小到大排序)
zrank xjzset 修己xj3
  • zrevrank 獲取指定成員的排名(分數從大到小排序)
zrevrank xjzset 修己xj3
  • zrange/zrevrange 獲取ZSET中指定排名范圍內的成員   zrange:分數從小到大排序,我們加了一些測試數據,如下

圖片圖片

zrevrange:分數從大到小排序

圖片圖片

zrange key start stop [withscores]

zrevrange key start stop [withscores]

其中,key是zset的鍵名,start是起始索引,stop結束索引,withscores表示是否同時返回分數。可以使用負數索引表示從末尾開始,比如-1表示最后一個元素。zrange key 0 -1 則會顯示出所有元素

zrange xjzset 1 2 withscores
  • zrangebyscore/zrevrangebyscore 獲取ZSET中指定分數score范圍內的成員  zrangebyscore:分數從小到大排序,zrevrangebyscore:分數從大到小排序
zrangebyscore key min max [withscores]

zrevrangebyscore key max min [withscores]

其中,key是zset的鍵名,min 和 max 表示score的范圍,范圍為閉區間,withscores表示是否同時返回分數。

zrangebyscore xjzset 2.5 3.5 withscores
  • zincrby 將指定成員的分數增加指定的值
zincrby xjzset  1  修己xj3

注: 進行double的值的運算時可能會丟失精度,如果對score進行運算時盡可能使用整數運算。

圖片圖片

  • zcard 返回zset中成員的數量
zcard xjzset
  • zcount 獲取指定范圍分數內的成員的數量
zcount key min max

其中,key是zset的鍵名,min 和 max 表示score的范圍,范圍為閉區間。

zcount  xjzset 0 2
  • zrem 刪除指定成員
zrem  xjzset
  • zremrangebyrank  刪除指定排名范圍內的成員
zremrangebyrank key start stop

其中,key是zset的鍵名,start是起始索引,stop結束索引。

zremrangebyrank xjzset 1 1
  • zremrangebyscore 刪除指定分數范圍內的成員
zremrangebyscore key min max

其中,key是zset的鍵名,min 和 max 表示score的范圍,范圍為閉區間。

zremrangebyscore  xjzset 0 3

圖片圖片

熱搜詞匯功能實現

我們設計思路是 將每個搜索詞作為有序集合的成員,而搜索次數作為成員的分數,每次搜索的時候對這個搜索詞的分數加1,這樣可以根據搜索次數對熱搜詞進行排序。

  • 搜索接口
public String keySearch(String keyStr){

    String hotSearchKey = "xj_hotSearch";
    RScoredSortedSet<String> hotSearchZSet = redissonClient.getScoredSortedSet(hotSearchKey);
    //更新zset中當前搜索詞的搜索次數
    hotSearchZSet.addScore(keyStr,1);
    //搜索邏輯
    //doSearch(keyStr);
    return keyStr;
}
  • 熱搜詞匯查詢接口
public Collection<String> hotSearch(){
    String hotSearchKey = "xj_hotSearch";
    RScoredSortedSet<String> hotSearchZSet = redissonClient.getScoredSortedSet(hotSearchKey);
    //獲取zset中點擊次數排名前5的數據
    Collection<String> hotList= hotSearchZSet.valueRangeReversed(0,4);
    return hotList;
}

我們加了一些測試數據,如下

圖片圖片

圖片圖片

總結

通過本文的介紹,你學會了如何利用Spring Boot和Redis的ZSET數據結構實現熱門搜索功能,并深入了解了熱搜詞匯的實現細節。通過合理的設計和優化,可以為用戶提供更好的搜索體驗,同時也提升了應用程序的性能和可擴展性。

責任編輯:武曉燕 來源: 修己xj
相關推薦

2025-03-10 12:10:00

RedisJava排行榜

2013-08-23 09:41:19

2022-06-17 12:10:07

RPA機器人流程自動化

2025-05-07 08:21:01

2014-07-30 12:56:56

2024-03-26 00:00:06

RedisZSet排行榜

2022-08-09 08:29:50

TIOBE編程語言排行榜程序員

2022-06-08 13:50:41

AI專業排行

2020-03-07 22:01:58

編程語言JavaPython

2019-10-21 10:59:52

編程語言JavaC

2019-07-23 14:14:59

編程語言JavaPython

2020-08-13 11:55:33

編程語言JavaPython

2020-02-14 09:19:12

編程語言JavaPython

2013-04-01 09:50:15

Web框架Web

2013-09-27 11:32:29

編程語言

2021-09-23 10:50:42

編程語言Python排行

2021-07-07 05:42:24

編程語言開發

2020-02-19 20:20:43

APP排行榜用戶

2023-03-15 08:03:31

2011-12-29 09:24:54

iOS應用下載排行榜
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 91免费福利在线 | 91在线看片 | 国产精品久久久久久久久久免费看 | 黄视频国产 | 干一干操一操 | 成人深夜福利 | 国产精品久久久久国产a级 欧美日韩国产免费 | 国产精品视频免费看 | 欧美亚州 | 亚洲成在线观看 | 国产在线激情视频 | 午夜免费视频 | 久久一日本道色综合久久 | 久久精品综合网 | 黄网站在线播放 | 日韩在线免费播放 | 国产日韩久久 | 国内精品一区二区 | 欧美黄色性生活视频 | 97成人精品| 福利视频网站 | 国产精品精品视频一区二区三区 | 一区二区三区久久 | 国产亚洲精品久久久久久豆腐 | 日本在线一二 | 孕妇一级毛片 | 亚洲精品99久久久久久 | 一区二区三区回区在观看免费视频 | 久久亚洲综合 | 亚洲午夜三级 | 亚洲色欧美另类 | 免费一区二区 | 国产一极毛片 | 国产中文字幕网 | 日韩在线观看一区 | 一级女毛片| 本地毛片 | 男人的天堂久久 | 国产一二三视频在线观看 | 亚洲一区视频在线 | 小h片免费观看久久久久 |