新聞中心

網(wǎng)站建設哪家好,找創(chuàng)新互聯(lián)!專注于網(wǎng)頁設計、網(wǎng)站建設、微信開發(fā)、小程序開發(fā)、集團企業(yè)網(wǎng)站建設等服務項目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了遵化免費建站歡迎大家使用!
zset 是 Redis 常用數(shù)據(jù)類型之一,它適用于排行榜類型的業(yè)務場景,比如 QQ 音樂排行榜、用戶貢獻榜等。在音樂排行榜單中,我們可以將歌曲的點擊次數(shù)作為 score 值,把歌曲的名字作為 value 值,通過對 score 排序就可以得出歌曲“熱度榜單”。
Redis 使用以下命令創(chuàng)建一個有序集合:
127.0.0.1:6379> ZADD key score member [score member ...]
key:指定一個鍵名;
score:分數(shù)值,用來描述 member,它是實現(xiàn)排序的關(guān)鍵;
member:要添加的成員(元素)。
當 key 不存在時,將會創(chuàng)建一個新的有序集合,并把分數(shù)/成員(score/member)添加到有序集合中;當 key 存在時,但 key 并非 zset 類型,此時就不能完成添加成員的操作,同時會返回一個錯誤提示。
注意:在有序集合中,成員是唯一存在的,但是分數(shù)(score)卻可以重復。有序集合的最大的成員數(shù)為 2^32 - 1 (大約 40 多億個)。
認識有序集合
1) 壓縮列表
有序集合(zset)同樣使用了兩種不同的存儲結(jié)構(gòu),分別是 zipList(壓縮列表)和 skipList(跳躍列表),當 zset 滿足以下條件時使用壓縮列表:
- 成員的數(shù)量小于128 個;
- 每個 member (成員)的字符串長度都小于 64 個字節(jié)。
下面對壓縮列表做簡單介紹,它由以下五部分組成,如圖所示:
上述每一部分在內(nèi)存中都是緊密相鄰的,并承擔著不同的作用,介紹如下:
- zlbytes 是一個無符號整數(shù),表示當前 ziplist 占用的總字節(jié)數(shù);
- zltail 指的是壓縮列表尾部元素相對于壓縮列表起始元素的偏移量。
- zllen 指 ziplist 中 entry 的數(shù)量。當 zllen 比
2^16 - 2大時,需要完全遍歷 entry 列表來獲取 entry 的總數(shù)目。 - entry 用來存放具體的數(shù)據(jù)項(score和member),長度不定,可以是字節(jié)數(shù)組或整數(shù),entry 會根據(jù)成員的數(shù)量自動擴容。
- zlend 是一個單字節(jié)的特殊值,等于 255,起到標識 ziplist 內(nèi)存結(jié)束點的作用。
下面執(zhí)行
ZADD命令添加兩個成員:xh(小紅) 的工資是 3500.0;xm(小明) 的工資是 3200.0。
ZADD salary 3500.0 xh 3200.0 xm
上述成員在壓縮列表中的布局,如下所示:
當 zset 使用壓縮列表保存數(shù)據(jù)時,entry 的第一個節(jié)點保存 member,第二個節(jié)點保存 score。依次類推,集合中的所有成員最終會按照 score 從小到大排列。
2) 跳躍列表
當有序結(jié)合不滿足使用壓縮列表的條件時,就會使用 skipList 結(jié)構(gòu)來存儲數(shù)據(jù)。
跳躍列表(skipList)又稱“跳表”是一種基于鏈表實現(xiàn)的隨機化數(shù)據(jù)結(jié)構(gòu),其插入、刪除、查找的時間復雜度均為 O(logN)。從名字可以看出“跳躍列表”,并不同于一般的普通鏈表,它的結(jié)構(gòu)較為復雜,本節(jié)只對它做淺顯的介紹,如有興趣可自行研究。
在 Redis 中一個 skipList 節(jié)點最高可以達到 64 層,一個“跳表”中最多可以存儲 2^64 個元素,每個節(jié)點都是一個 skiplistNode(跳表節(jié)點)。skipList 的結(jié)構(gòu)體定義如下:
typedf struct zskiplist{
//頭節(jié)點
struct zskiplistNode *header;
//尾節(jié)點
struct zskiplistNode *tail;
// 跳表中的元素個數(shù)
unsigned long length;
//表內(nèi)節(jié)點的最大層數(shù)
int level;
}zskiplist;
- header:指向 skiplist 的頭節(jié)點指針,通過它可以直接找到跳表的頭節(jié)點,時間復雜度為 O(1);
- tail:指向 skiplist 的尾節(jié)點指針,通過它可以直接找到跳表的尾節(jié)點,時間復雜度為 O(1);
- length:記錄 skiplist 的長度,也就跳表中有多少個元素,但不包括頭節(jié)點;
- level:記錄當前跳表內(nèi)所有節(jié)點中的最大層數(shù)(level);
跳躍列表的每一層都是一個有序的鏈表,鏈表中每個節(jié)點都包含兩個指針,一個指向同一層的下了一個節(jié)點,另一個指向下一層的同一個節(jié)點。最低層的鏈表將包含 zset 中的所有元素。如果說一個元素出現(xiàn)在了某一層,那么低于該層的所有層都將包含這個元素,也就說高層是底層的子集。
通過以下示意圖進一步認識 skiplist 結(jié)構(gòu)。下圖是一個上下共四層的跳躍列表結(jié)構(gòu):
圖1:跳躍列表示意圖
跳躍列表中的每個節(jié)點都存儲著 S:V(即 score/value),示意圖顯示了使用跳躍列表查找 S:V 節(jié)點的過程。跳躍列表的層數(shù)由高到低依次排列,最低層是 L0 層,最高層是 L3 層,共有 4 層。
圖 1 所示,首先從最高層開始遍歷找到第一個
S:V節(jié)點,然后從此節(jié)點開始,逐層下降,通過遍歷的方式找出每一層的 S:V 節(jié)點,直至降至最底層(L0)才停止。在這個過程中找到所有 S:V 節(jié)點被稱為期望的節(jié)點。跳躍列表把上述搜索一系列期望節(jié)點的過程稱為“搜索路徑”,這個“搜索路徑”由搜索到的每一層的期望節(jié)點組成,其本質(zhì)是一個列表。
常用命令匯總
| 命令 | 說明 |
|---|---|
| ZADD key score1 member1 [score2 member2] | 用于將一個或多個成員添加到有序集合中,或者更新已存在成員的 score 值 |
| ZCARD key | 獲取有序集合中成員的數(shù)量 |
| ZCOUNT key min max | 用于統(tǒng)計有序集合中指定 score 值范圍內(nèi)的元素個數(shù)。 |
| ZINCRBY key increment member | 用于增加有序集合中成員的分值。 |
| ZINTERSTORE destination numkeys key [key ...] | 求兩個或者多個有序集合的交集,并將所得結(jié)果存儲在新的 key 中。 |
| ZLEXCOUNT key min max | 當成員分數(shù)相同時,計算有序集合中在指定詞典范圍內(nèi)的成員的數(shù)量。 |
| ZRANGE key start stop [WITHSCORES] | 返回有序集合中指定索引區(qū)間內(nèi)的成員數(shù)量。 |
| ZRANGEBYLEX key min max [LIMIT offset count] | 返回有序集中指定字典區(qū)間內(nèi)的成員數(shù)量。 |
| ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT] | 返回有序集合中指定分數(shù)區(qū)間內(nèi)的成員。 |
| ZRANK key member | 返回有序集合中指定成員的排名。 |
| ZREM key member [member ...] | 移除有序集合中的一個或多個成員。 |
| ZREMRANGEBYLEX key min max | 移除有序集合中指定字典區(qū)間的所有成員。 |
| ZREMRANGEBYRANK key start stop | 移除有序集合中指定排名區(qū)間內(nèi)的所有成員。 |
| ZREMRANGEBYSCORE key min max | 移除有序集合中指定分數(shù)區(qū)間內(nèi)的所有成員。 |
| ZREVRANGE key start stop [WITHSCORES] | 返回有序集中指定區(qū)間內(nèi)的成員,通過索引,分數(shù)從高到低。 |
| ZREVRANGEBYSCORE key max min [WITHSCORES] | 返回有序集中指定分數(shù)區(qū)間內(nèi)的成員,分數(shù)從高到低排序。 |
| ZREVRANK key member | 返回有序集合中指定成員的排名,有序集成員按分數(shù)值遞減(從大到小)排序。 |
| ZSCORE key member | 返回有序集中,指定成員的分數(shù)值。 |
| ZUNIONSTORE destination numkeys key [key ...] | 求兩個或多個有序集合的并集,并將返回結(jié)果存儲在新的 key 中。 |
| ZSCAN key cursor [MATCH pattern] [COUNT count] | 迭代有序集合中的元素(包括元素成員和元素分值)。 |
基本命令演示
下面通過一組命令,讓我們熟悉如何操作 zset 數(shù)據(jù)類型。以下示例是一個保存了員工薪水的有序集合:
#在有序集合中添加一個成員 127.0.0.1:6379> ZADD salary 4000 lucy (integer) 1 #同時添加多個成員 127.0.0.1:6379> ZADD salary 5000 tom 6000 Helen 6500.50 Jack 3000 Smith (integer) 4 #查詢指定區(qū)間上的元素 127.0.0.1:6379> ZRANGE salary 0 4 1) "Smith" 2) "lucy" 3) "tom" 4) "Helen" 5) "Jack" #降序查看指定區(qū)間上的元素 127.0.0.1:6379> ZREVRANGE salary 0 4 1) "Jack" 2) "Helen" 3) "tom" 4) "lucy" 5) "Smith" #查看指定元素的分值 127.0.0.1:6379> ZSCORE salary lucy "4000" #查看所有元素和分值 127.0.0.1:6379> ZRANGE salary 0 4 WITHSCORES 1) "Smith" 2) "3000" 3) "lucy" 4) "4000" 5) "tom" 6) "5000" 7) "Helen" 8) "6000" 9) "Jack" 10) "6500.5" #統(tǒng)計指定工資范圍內(nèi)的元素個數(shù)3000<=score<=5000 127.0.0.1:6379> ZCOUNT salary 3000 5000 (integer) 3 #表示3000ZCOUNT salary (3000 (5000 (integer) 1 #返回指定工資范圍內(nèi)的score和成員,限制條件是跳過1個元素,返回2個元素。 127.0.0.1:6379> ZRANGEBYSCORE salary 3000 6000 WITHSCORES LIMIT 1 2 1) "lucy" 2) "4000" 3) "tom" 4) "5000" #查看有序集合在指定字典區(qū)間內(nèi)的成員的數(shù) #其中 - 表示最小值,而 + 則表示最大值 127.0.0.1:6379> ZLEXCOUNT salary - + (integer) 5
在線練習工具:https://try.redis.io/
查看更多命令:https://redis.io/commands
名稱欄目:Rediszset有序集合(底層原理+圖解)
標題網(wǎng)址:http://m.fisionsoft.com.cn/article/coghhep.html


咨詢
建站咨詢
