初識Redis · set和zset

目錄

前言:

set

基本命令

交集并集差集

內部編碼和應用場景

zset

基本命令

交集并集差集

內部編碼和應用場景

應用場景(AI生成)

排行榜系統

應用背景

設計思路

熱榜系統

應用背景

設計思路

熱度計算方式

總結對比表


前言:

在前幾篇Redis的基本數據類型中,我們已經了解了string list hash,并且了解了對應的內部編碼和實際的應用場景,也是對于基本的命令操作花了比較多的文字描述的去介紹。那么在本文呢,既然有了前幾個類型多個基礎,我們學習set和zset也是會比較輕松的了。

廢話不多說,我們直接進入主題吧。


set

基本命令

首先,set它是代表集合的意思,那么對于它來說,存在的幾個特點有:無序的,不可重復的,那么因為無序,它也就不存在索引的特點。

既然是集合,我們曾經在高中階段,或者是大學階段均接觸過集合的概念,對于集合來說有的基本操作有交集并集差集,在Redis中也存在這幾個操作,所以這里的set雖然說和C++中的set差別比較大,但是和數學中的集合還是挺有相同點的。

sadd:給集合中添加元素,返回值為添加成功了幾個元素

因為集合是去重的,所以我們重復添加元素的話,是會添加失敗的。

smembers:查看集合中的元素?

sismember: 判斷元素是否在集合內部

不過sismember只能判斷一個元素,其實對于這種命令來說我們甚至可以通過翻譯的方式判斷它是什么意思,比如sismember,s代表set is的意思代表是 member代表成員,那么sismember的意思就是是否是set的成員。所以我們也沒有必要專門記命令。

scard:查詢set中有多少個元素

spop:隨機刪除一個元素

注意,這里的隨機是真的隨機,我們也可以通過驗證的方式判斷是否是隨機的,第一次是1 4,第二次是1 3,不存在任何的順序。這其實就有點意思了,隨機刪除。

至于為什么是隨機的呢,可能也和set本身是無序的有關系吧,而且官方文檔也明確說了spop是隨機的,并且在源碼中也是使用的生成隨機數的方式的:

既然我們現在提到了無序,我們可以簡單引出一個話題,即什么是有序的?

其實對于有序來說,分為有順序和排名有序的,比如我們拿set來說,有1 2 3 4和4 1 3 2的兩種情況的set都是一樣的,拿list來說,1 2 3 4和 1 2 4 3的兩種不是一樣的,因為list是有序的,但是以上我們兩種說的有序的都是指的是有順序的。對于有順序的話,比如排名一類的,就是有序的,但是這個有序的是指按照某種權重進行排序的,而非順序上的有序。

以上是對有序這個詞的討論。

smove:將某個元素從source移動到destination

不過要是沒有這個元素,也就返回0了。

srem:將某個元素從key中刪除。

這里的rem代表的意思是remove,即移除的意思,它的返回值的意思是刪除成功的元素的個數。

交集并集差集

對于集合之間的運算涉及到的命令是:sinter,sunion,sdiff,sinterstore,sunionstore,sdiffstore。

sinter:求多個集合的交集

比如sinter key key1就是求兩個key之間的交集,我們也可以求多個,不過我們設置的多個集合之間并沒有交集,所以什么也沒有返回。

sinterstore:求多個集合之間的交集并存在一個集合中

我們倒是發現了一個有意思的點是,key2原本的數據被清空了,只剩下了求完交集之后的元素。以上兩個命令的時間復雜度是O(N*M),N和M分別代表的是最小的集合元素個數和最大的集合元素個數。

sunion,sunionstore:求并集元素(并把并集的元素放在另一個集合中)。

同樣,還是具備清空的效果,那么對于以上兩個命令的時間復雜度是O(N),這個N是總的元素個數。

有意思的是,不管我們如何更換求交集或者并集的set的次序,結果都是不會改變的,而差集不一樣,差集存在一定的次序問題,比如sdiff key1 key2 和sdiff key2 key1之間的結果是不同的,因為差集的定義是key1中有的而key2中沒有的,反過來肯定就不一樣了:

就像這樣。

同理,它的時間復雜度還是O(N),因為要遍歷所有的元素,但是具體怎么實現的,就是Redis內部源碼的實現了,我們后面更新。

以上就是Redis中set的基本命令了。

內部編碼和應用場景

對于set來說,它內部的編碼方式分為了兩種,一種是intset一種是hashtable,如果set內部的元素是整數并且數據個數不多的就是使用的intset,如果是字符串一類的,那么就是hashtable了:

而且我們也能發現,內部編碼方式一旦確定了,也是不太好輕易發生修改的。

它的應用場景的話也是非常顯然的,比如使用QQ的時候,我們經常會收到某某某和你有多少個共同好友,是否加他為好友?這其實就是set求交集的結果,set也可以用來保存用戶的標簽,而用戶的標簽是多樣化的,因為千人千面嘛,所以對于用戶數據來說很多都是公司是共享的,比如A軟件的用戶數據有青年,18歲,喜歡看美女,B軟件的用戶數據有青年,18歲,喜歡跑車,那么就有一種業務是讓兩個公司對接一下用戶數據。

這樣用戶的互聯網畫像也就是越來越完整了。

還有一個非常經典的應用場景是:用Set統計PV和UV數據。同學可自行下來探索~


zset

基本命令

對于zset和set來說,zset的特點是有序的,這里的有序代表的就是用權重來進行排序了

就像這張表一樣,不同的三國猛將用武將值來進行排序,這樣就構成了一個zset,不過因為引入了分數的概念,那么對于zset來說,它的命令操作自然就要復雜的多了。

不過我們首先引入一個問題,因為zset中元素是不允許重復的,分數是可以重復的,如果分數重復了,如何進行排序呢?實際上就按照元素的字典序來進行排序

既然引入了分數的概念,我們需要認識到一個點是zset存儲的是元素,對于分數來說,它只是一個輔助工具而已。

zadd:向集合添加元素,不過這里涉及到了一些選項,比如NX|XX GT|LT INCR等 。

我們一個一個來,先是最普通的應用:

我們插入了之后,可以通過zrange查看,其中如果要帶有分數的查看,就加上withscores就行了,這里默認的是升序,咱們雖然說zset是有序的,有序無非是升序和降序,對于zset來說默認的就是升序了。

對于選項,NX和XX 與之前我們學習string的時候有點差別

string是對key存在性的判斷,zset是對成員存在性的判斷。

因為兩個成員都存在,所以自然就添加失敗,對于XX來說,就更像是一種更新了:

而對于zadd來說它的返回值是新增了的元素個數(并不包括更新的元素)

對于LT和GT官方的描述是這樣的,如果要更新元素,那么LT代表是less than,GT代表的是greater than,如果分數小于原來的就更新或者分數如果大于原來的就更新。

不過不幸的是,GT和LT是6.2之后才有的,我們的版本沒到那里,所以我們先了解一下。

接著是CH,它的作用就是更改返回值,因為zadd的返回值是只返回新增加的元素,對于更新的元素是不管的,那么CH就是加上了更新的元素

最后是incr,它其實就是用來單個增加分數的,和之前的incr hincr沒啥區別:?

它類似的有這個命令

但是zadd已經可以完成了。

這個命令的時間復雜度是logN:

它不像之前的hash list set一樣的時間復雜度為O(1),它因為是有序的,并且要找到對應的位置,所以在它內部實現的時候,使用跳表利用有序的特點找到對應的位置。

zcard:查看集合中的所有元素

返回值是有幾個元素。

但是因為引入了分數的概念,所以我們也可以使用zcount指定區間查看對應的元素個數:

那么我們想用zcount實現成zcard的效果,我們就可以:

使用inf,inf代表的是無窮大,那么我們指定閉區間為負無窮大到無窮大,就可以完成所有元素的遍歷。

它的時間復雜度是O(logN)其中主要是為了找到Min和max對應的位置,然后因為zset內部會記錄每個元素當前的次序,找到了之后做個減法,就可以得到對應的結果了。

不過這里有一個比較反人類的設定,如果我們想要設置為開區間,就在想要設置為開區間的元素前面加一個(即可:

zrevrange:逆序遍歷,這個是對上面zrange的補充。

但是對應的索引是不變的。

既然我們可以通過索引來查看元素,我們是否也可以通過分數來查看呢?

使用命令zrangebyscore即可

zpopmax:刪除最高分數的count個元素

首先我們先記住,它的時間復雜度是O(M * logN),其中N是key中的總元素,M是count的,我們有基礎的話,很難不去想對于刪除一個有序的特殊位置,比如尾部,它的時間復雜度是logN而不是O(1),這就讓人有點疑惑了,因為按照Redis的技術是完全可以的,但是咱也不知道為啥沒有優化,可能是技術人員認為優化這里完全沒有必要,因為LogN已經很快了,所以在zpopmax的內部還是調用的通用的刪除函數:

Bzpopmax:按照阻塞的方式刪除最高分數的count個元素

和前面學習的blpop一摸一樣的,它也是能夠一次性檢測多個key。它的時間復雜度是O(M * logN),這個M不是監測了幾個key的M,而是在key上刪除了元素的key個數。

zpopmin和bzpopmin:(按照阻塞的方式)刪除最低分數的count個元素,因為用法幾乎是一樣的,所以咱在這里啊 也就不演示了。

zrank和zrevrank:從前往后(從后往前)計算對應的排名,對應的時間復雜度是O(logN)

zscore:返回對應member的分數,時間復雜度是O(1),這里的話就是Redis針對進行特殊的優化的,是采取了空間換時間的做法

zrem和zremrangebyrank:(根據排名)刪除元素

有趣的是,根據排名的時候是可以使用負數的,-1代表的就是最后一名,不過用法還是從前往后的,時間復雜度是logN + M,其中N是成員總數,M是區間個數。

zincrby:調整某個元素的分數

但是改變了分數之后,整體還是會保持升序的。

交集并集差集

這里涉及到的命令有:zunion,zinter,zdiff,不過這三個命令都是6.2版本才開始支持,我們這里就暫時不討論,我們這里討論兩個命令,一個是zinterstore,一個是zunionstore

destination代表的存儲到這個key里面,numbers代表的是有幾個集合參與運算,weights代表的是權重,雖然說是不同的key進行運算,但是根據實際情況不同的key自己的份量不同,所以運算的時候分數會乘上我們給定的權重,然后就是合并的時候,是總和呢還是最小的還是最大的,就是最后一個參數了,默認是按照總和。

這里使用到了numkeys來指定集合數,就非常像我們之前學習http的時候,報頭里面有一個字段是正文部分的長度,如果這里出現了問題,就會導致粘包問題。

就像這樣。

主要涉及到的還是score的計算,那你說,zunionstore的使用是不是一樣的?完全一樣嘛,所以這里就不演示了。

內部編碼和應用場景

它的內部編碼方式有ziplist和skiplist,如果元素較少,單個元素體積小,就使用ziplist,反之就使用skiplist,不過對于這里的ziplist還是使用的空間換取時間的做法,自然就不敢元素多了還用ziplist了。

明白啦,下面是為博客撰寫的純文字版內容,格式整潔、內容完整,可直接復制粘貼上傳到博客平臺(如 CSDN、掘金、個人博客等):


應用場景(AI生成)

排行榜系統

應用背景

排行榜常用于游戲、競賽、學習平臺等系統中,主要用來展示用戶在某項指標上的相對排名,例如積分榜、活躍度榜、勝率榜等。系統要求能夠快速地更新用戶得分、獲取前幾名用戶,以及查詢某個用戶的實時排名。

設計思路

在排行榜中,每個用戶對應一個唯一標識(如用戶 ID),而其得分則用于排序依據。Redis 的有序集合能夠很好地完成這項任務。它會根據用戶得分自動維持從低到高的順序,同時支持查詢、更新、分頁等操作。

為了方便擴展,不同類型的排行榜可以用不同的 key 名進行管理,比如設置日榜、周榜、總榜等。

熱榜系統

應用背景

在內容平臺或社區系統中,文章、帖子或視頻的“熱度”是衡量內容受歡迎程度的重要指標。平臺通常會根據內容的瀏覽量、點贊數、評論量等因素,計算一個熱度得分,并據此展示熱門內容排行榜。

與普通排行榜不同,文章熱度往往涉及多維因素,還可能加入時間衰減,以保持榜單的新鮮感,避免長期霸榜。

設計思路

在 Redis 中,可以將每篇文章的唯一標識作為 ZSet 成員,將計算后的熱度值作為排序依據。每當文章發生交互行為時(例如點贊、被瀏覽、被評論等),系統即可對其熱度進行更新。

為了支持多分類內容推薦,也可以為不同的內容類別創建獨立的熱度榜,例如科技類、娛樂類、教育類等,每個分類對應一個有序集合。

熱度計算方式

熱度得分通常不是單一數據,而是由多個指標加權計算而來。例如,可以設定一個公式,綜合點擊量、點贊量、評論量等數據;還可以為舊文章引入時間衰減機制,防止內容因早期流量過大而長期占據榜單。

最終熱度值由業務邏輯層計算完成,再寫入 Redis 中的有序集合。


總結對比表

功能需求排行榜系統文章熱度榜
目標成員用戶 ID文章 ID
分數含義積分、活躍度熱度(閱讀、點贊等加權計算)
更新頻率實時(如游戲加分)實時或周期更新(如點贊、點擊)
查詢方式Top N、用戶排名、分頁熱榜分頁、熱度值查詢
清理策略刪除低排名用戶,節省空間刪除冷文章,保持熱榜實時性

感謝閱讀!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/76105.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/76105.shtml
英文地址,請注明出處:http://en.pswp.cn/web/76105.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

playwright 教程高級篇:掌握網頁自動化與驗證碼處理等關鍵技術詳解

Playwright 教程高級篇:掌握網頁自動化與驗證碼處理等關鍵技術詳解 本教程將帶您一步步學習如何使用 Playwright——一個強大的瀏覽器自動化工具,來完成網頁任務,例如提交鏈接并處理旋轉驗證碼。我們將按照典型的自動化流程順序,從啟動瀏覽器到關閉瀏覽器,詳細講解每個步驟…

數據結構(完)

樹 二叉樹 構建二叉樹 int value;Node left;Node right;public Node(int val) {valueval;} 節點的添加 Node rootnull;public void insert(int num) {Node nodenew Node(num);if(rootnull) {rootnode;return;}Node index root;while(true) {//插入的節點值小if(index.value&g…

FastAPI與SQLAlchemy數據庫集成與CRUD操作

title: FastAPI與SQLAlchemy數據庫集成與CRUD操作 date: 2025/04/16 09:50:57 updated: 2025/04/16 09:50:57 author: cmdragon excerpt: FastAPI與SQLAlchemy集成基礎包括環境準備、數據庫連接配置和模型定義。CRUD操作通過數據訪問層封裝和路由層實現,確保線程安全和事務…

一個基于Django的寫字樓管理系統實現方案

一個基于Django的寫字樓管理系統實現方案 用戶現在需要我用Django來編寫一個寫字樓管理系統的Web版本,要求包括增刪改查寫字樓的HTML頁面,視頻管理功能,本地化部署,以及人員權限管理,包含完整的代碼結構和功能實現&am…

mongodb在window10中創建副本集的方法,以及node.js連接副本集的方法

創建Mongodb的副本集最好是新建一個文件夾,如D:/data,不要在mongodb安裝文件夾里面創建副本集,雖然這樣也可以,但是容易造成誤操作或路徑混亂;在新建文件夾里與現有 MongoDB 數據隔離,避免誤操作影響原有數…

Maven 多倉庫與鏡像配置全攻略:從原理到企業級實踐

Maven 多倉庫與鏡像配置全攻略:從原理到企業級實踐 一、核心概念:Repository 與 Mirror 的本質差異 在 Maven 依賴管理體系中,repository與mirror是構建可靠依賴解析鏈的兩大核心組件,其核心區別如下: 1. Repositor…

STM32 四足機器人常見問題匯總

文章不介紹具體參數,有需求可去網上搜索。 特別聲明:不論年齡,不看學歷。既然你對這個領域的東西感興趣,就應該不斷培養自己提出問題、思考問題、探索答案的能力。 提出問題:提出問題時,應說明是哪款產品&a…

MySQL 中 `${}` 和 `#{}` 占位符詳解及面試高頻考點

文章目錄 一、概述二、#{} 和 ${} 的核心區別1. 底層機制代碼示例 2. 核心區別總結 三、為什么表名只能用 ${}?1. 預編譯機制的限制2. 動態表名的實現 四、安全性注意事項1. ${} 的風險場景2. 安全實踐 五、面試高頻考點1. 基礎原理類問題**問題 1**:**問…

C語言編譯預處理2

#include <XXXX.h>和#include <XXXX.c> #include "XXXX.h" 是 C 語言中一條預處理指令 #include <XXXX.h>&#xff1a;這種形式用于包含系統標準庫的頭文件。預處理器會在系統默認的頭文件搜索路徑中查找XXXX.h 文件。例如在 Linux 系統中&#…

Elasticvue-輕量級Elasticsearch可視化管理工具

Elasticvue一個免費且開源的 Elasticsearch 在線可視化客戶端&#xff0c;用于管理 Elasticsearch 集群中的數據&#xff0c;完全支持 Elasticsearch 版本 8.x 和 7.x. 功能特色&#xff1a; 集群概覽索引和別名管理分片管理搜索和編輯文檔REST 查詢快照和存儲庫管理支持國際…

Git提交規范及最佳實踐

Git 提交規范通常是為了提高代碼提交的可讀性、可維護性和自動化效率&#xff08;如生成 ChangeLog&#xff09;。以下是常見的 Conventional Commits 規范&#xff0c;結合社區最佳實踐總結而成&#xff1a; 1. 提交格式 每次提交的 commit message 應包含三部分&#xff1a;…

Ubuntu中snap

通過Snap可以安裝眾多的軟件包。需要注意的是&#xff0c;snap是一種全新的軟件包管理方式&#xff0c;它類似一個容器擁有一個應用程序所有的文件和庫&#xff0c;各個應用程序之間完全獨立。所以使用snap包的好處就是它解決了應用程序之間的依賴問題&#xff0c;使應用程序之…

android studio 運行java main報錯

運行某個帶main函數的java文件報錯 Could not create task :app:Test.main(). > SourceSet with name main not found. 解決辦法&#xff1a;在工程的.idea/gradle.xml 文件下添加&#xff1a; <option name"delegatedBuild" value"false" /&g…

openssh離線一鍵升級腳本分享(含安裝包)

查看當前的版本 [rootmyoracle ~]#ssh -V相關安裝包下載地址 openssh下載地址&#xff1a;http://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssl下載地址&#xff1a;https://www.openssl.org/source/zlib下載地址&#xff1a;http://www.zlib.net/今天演示從7.4升級…

Mac M1管理多個Node.js版本

目錄 1. 使用 nvm (Node Version Manager) 1.1.安裝 nvm 1.2.安裝Node.js版本 1.3.查看已安裝的node版本列表 1.4.使用特定版本的Node.js 1.5.查看當前使用的版本 2. 使用 fnm (Fast Node Manager) 2.1.安裝 fnm 2.2.安裝Node.js版本 2.3.查看已安裝的版本 2.4.使用…

Unity中國戰略調整簡訊:Unity6下架 團結引擎接棒

Unity中國戰略調整簡訊&#xff1a;Unity6下架 團結引擎接棒 免費版 2025年4月9日 —— Unity中國宣布自即日起&#xff0c;中國大陸及港澳地區停止提供Unity 6及后續版本下載與服務&#xff0c;相關功能由國產引擎“團結引擎”承接。國際版2022 LTS及更早版本仍由Unity中國維護…

TestNG 單元測試詳解

1、測試環境 jdk1.8.0 121 myeclipse-10.0-offline-installer-windows.exe TestNG 插件 org.testng.eclipse 6.8.6.20130607 0745 2、介紹 套件(suite):由一個 XML 文件表示,通過<suite>標簽定義,包含一個或更多測試(test)。測試(test):由<test>定義&#xf…

C復習(主要復習)

指針和數組 指針數組是一個數組&#xff0c;數組的每個元素都是指針。它適用于需要存儲多個指針的場景&#xff0c;如字符串數組。數組指針是一個指針&#xff0c;指向一個數組。它適用于需要傳遞整個數組給函數或處理多維數組的場景。 函數指針&#xff1a;函數指針的定義需要…

探索大語言模型(LLM):定義、發展、構建與應用

文章目錄 引言大規模語言模型的基本概念大規模語言模型的發展歷程1. 基礎模型階段&#xff08;2018年至2021年&#xff09;2. 能力探索階段&#xff08;2019年至2022年&#xff09;3. 突破發展階段&#xff08;以2022年11月ChatGPT的發布為起點&#xff09; 大規模語言模型的構…

5. k8s 之 pod原理與使用

Kubernetes Pod 原理詳解 1. Pod 的部署方式 Pod 是 Kubernetes 的最小調度單元&#xff0c;其部署方式分為 聲明式&#xff08;YAML&#xff09; 和 命令式&#xff08;kubectl&#xff09; 兩種&#xff1a; (1) 聲明式部署&#xff08;推薦&#xff09; 通過 YAML 文件定…