日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Rediszset有序集合(底層原理+圖解)
顧名思義,Redis zset(有序集合)中的成員是有序排列的,它和 set 集合的相同之處在于,集合中的每一個(gè)成員都是字符串類型,并且不允許重復(fù);而它們最大區(qū)別是,有序集合是有序的,set 是無序的,這是因?yàn)橛行蚣现忻總€(gè)成員都會(huì)關(guān)聯(lián)一個(gè) double(雙精度浮點(diǎn)數(shù))類型的 score (分?jǐn)?shù)值),Redis 正是通過 score 實(shí)現(xiàn)了對(duì)集合成員的排序。

網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)!專注于網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、小程序開發(fā)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了遵化免費(fèi)建站歡迎大家使用!

zset 是 Redis 常用數(shù)據(jù)類型之一,它適用于排行榜類型的業(yè)務(wù)場景,比如 QQ 音樂排行榜、用戶貢獻(xiàn)榜等。在音樂排行榜單中,我們可以將歌曲的點(diǎn)擊次數(shù)作為 score 值,把歌曲的名字作為 value 值,通過對(duì) score 排序就可以得出歌曲“熱度榜單”。

Redis 使用以下命令創(chuàng)建一個(gè)有序集合:

127.0.0.1:6379> ZADD key score member [score member ...]  

key:指定一個(gè)鍵名;

score:分?jǐn)?shù)值,用來描述  member,它是實(shí)現(xiàn)排序的關(guān)鍵;

member:要添加的成員(元素)。

當(dāng) key 不存在時(shí),將會(huì)創(chuàng)建一個(gè)新的有序集合,并把分?jǐn)?shù)/成員(score/member)添加到有序集合中;當(dāng) key 存在時(shí),但 key 并非 zset 類型,此時(shí)就不能完成添加成員的操作,同時(shí)會(huì)返回一個(gè)錯(cuò)誤提示。

注意:在有序集合中,成員是唯一存在的,但是分?jǐn)?shù)(score)卻可以重復(fù)。有序集合的最大的成員數(shù)為 2^32 - 1 (大約 40 多億個(gè))。

認(rèn)識(shí)有序集合

1) 壓縮列表

有序集合(zset)同樣使用了兩種不同的存儲(chǔ)結(jié)構(gòu),分別是 zipList(壓縮列表)和 skipList(跳躍列表),當(dāng) zset 滿足以下條件時(shí)使用壓縮列表:

  • 成員的數(shù)量小于128 個(gè);
  • 每個(gè) member (成員)的字符串長度都小于 64 個(gè)字節(jié)。

下面對(duì)壓縮列表做簡單介紹,它由以下五部分組成,如圖所示:

上述每一部分在內(nèi)存中都是緊密相鄰的,并承擔(dān)著不同的作用,介紹如下:

  • zlbytes 是一個(gè)無符號(hào)整數(shù),表示當(dāng)前 ziplist 占用的總字節(jié)數(shù);
  • zltail 指的是壓縮列表尾部元素相對(duì)于壓縮列表起始元素的偏移量。
  • zllen 指 ziplist 中 entry 的數(shù)量。當(dāng) zllen 比2^16 - 2大時(shí),需要完全遍歷 entry 列表來獲取 entry 的總數(shù)目。
  • entry 用來存放具體的數(shù)據(jù)項(xiàng)(score和member),長度不定,可以是字節(jié)數(shù)組或整數(shù),entry 會(huì)根據(jù)成員的數(shù)量自動(dòng)擴(kuò)容。
  • zlend 是一個(gè)單字節(jié)的特殊值,等于 255,起到標(biāo)識(shí) ziplist 內(nèi)存結(jié)束點(diǎn)的作用。

下面執(zhí)行
ZADD命令添加兩個(gè)成員:xh(小紅) 的工資是 3500.0;xm(小明) 的工資是 3200.0。

ZADD salary 3500.0 xh 3200.0 xm

上述成員在壓縮列表中的布局,如下所示:

當(dāng) zset 使用壓縮列表保存數(shù)據(jù)時(shí),entry 的第一個(gè)節(jié)點(diǎn)保存 member,第二個(gè)節(jié)點(diǎn)保存 score。依次類推,集合中的所有成員最終會(huì)按照 score 從小到大排列。

2) 跳躍列表

當(dāng)有序結(jié)合不滿足使用壓縮列表的條件時(shí),就會(huì)使用 skipList 結(jié)構(gòu)來存儲(chǔ)數(shù)據(jù)。

跳躍列表(skipList)又稱“跳表”是一種基于鏈表實(shí)現(xiàn)的隨機(jī)化數(shù)據(jù)結(jié)構(gòu),其插入、刪除、查找的時(shí)間復(fù)雜度均為 O(logN)。從名字可以看出“跳躍列表”,并不同于一般的普通鏈表,它的結(jié)構(gòu)較為復(fù)雜,本節(jié)只對(duì)它做淺顯的介紹,如有興趣可自行研究。

在 Redis 中一個(gè) skipList 節(jié)點(diǎn)最高可以達(dá)到 64 層,一個(gè)“跳表”中最多可以存儲(chǔ) 2^64 個(gè)元素,每個(gè)節(jié)點(diǎn)都是一個(gè) skiplistNode(跳表節(jié)點(diǎn))。skipList 的結(jié)構(gòu)體定義如下:

typedf struct zskiplist{
    //頭節(jié)點(diǎn)
    struct zskiplistNode *header;
    //尾節(jié)點(diǎn)
    struct zskiplistNode *tail;
    // 跳表中的元素個(gè)數(shù)
    unsigned long length;
    //表內(nèi)節(jié)點(diǎn)的最大層數(shù)
    int level;
}zskiplist;
  • header:指向 skiplist 的頭節(jié)點(diǎn)指針,通過它可以直接找到跳表的頭節(jié)點(diǎn),時(shí)間復(fù)雜度為 O(1);
  • tail:指向 skiplist 的尾節(jié)點(diǎn)指針,通過它可以直接找到跳表的尾節(jié)點(diǎn),時(shí)間復(fù)雜度為 O(1);
  • length:記錄 skiplist 的長度,也就跳表中有多少個(gè)元素,但不包括頭節(jié)點(diǎn);
  • level:記錄當(dāng)前跳表內(nèi)所有節(jié)點(diǎn)中的最大層數(shù)(level);

跳躍列表的每一層都是一個(gè)有序的鏈表,鏈表中每個(gè)節(jié)點(diǎn)都包含兩個(gè)指針,一個(gè)指向同一層的下了一個(gè)節(jié)點(diǎn),另一個(gè)指向下一層的同一個(gè)節(jié)點(diǎn)。最低層的鏈表將包含 zset 中的所有元素。如果說一個(gè)元素出現(xiàn)在了某一層,那么低于該層的所有層都將包含這個(gè)元素,也就說高層是底層的子集。 

通過以下示意圖進(jìn)一步認(rèn)識(shí) skiplist 結(jié)構(gòu)。下圖是一個(gè)上下共四層的跳躍列表結(jié)構(gòu):



圖1:跳躍列表示意圖

 

跳躍列表中的每個(gè)節(jié)點(diǎn)都存儲(chǔ)著 S:V(即 score/value),示意圖顯示了使用跳躍列表查找 S:V 節(jié)點(diǎn)的過程。跳躍列表的層數(shù)由高到低依次排列,最低層是 L0 層,最高層是 L3 層,共有 4 層。

圖 1 所示,首先從最高層開始遍歷找到第一個(gè)
S:V節(jié)點(diǎn),然后從此節(jié)點(diǎn)開始,逐層下降,通過遍歷的方式找出每一層的 S:V 節(jié)點(diǎn),直至降至最底層(L0)才停止。在這個(gè)過程中找到所有 S:V 節(jié)點(diǎn)被稱為期望的節(jié)點(diǎn)。跳躍列表把上述搜索一系列期望節(jié)點(diǎn)的過程稱為“搜索路徑”,這個(gè)“搜索路徑”由搜索到的每一層的期望節(jié)點(diǎn)組成,其本質(zhì)是一個(gè)列表。

常用命令匯總

有序集合常用命令
命令 說明
ZADD key score1 member1 [score2 member2] 用于將一個(gè)或多個(gè)成員添加到有序集合中,或者更新已存在成員的 score 值
ZCARD key 獲取有序集合中成員的數(shù)量
ZCOUNT key min max 用于統(tǒng)計(jì)有序集合中指定 score 值范圍內(nèi)的元素個(gè)數(shù)。
ZINCRBY key increment member 用于增加有序集合中成員的分值。
ZINTERSTORE destination numkeys key [key ...] 求兩個(gè)或者多個(gè)有序集合的交集,并將所得結(jié)果存儲(chǔ)在新的 key 中。
ZLEXCOUNT key min max 當(dāng)成員分?jǐn)?shù)相同時(shí),計(jì)算有序集合中在指定詞典范圍內(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] 返回有序集合中指定分?jǐn)?shù)區(qū)間內(nèi)的成員。
ZRANK key member 返回有序集合中指定成員的排名。
ZREM key member [member ...] 移除有序集合中的一個(gè)或多個(gè)成員。
ZREMRANGEBYLEX key min max 移除有序集合中指定字典區(qū)間的所有成員。
ZREMRANGEBYRANK key start stop 移除有序集合中指定排名區(qū)間內(nèi)的所有成員。
ZREMRANGEBYSCORE key min max 移除有序集合中指定分?jǐn)?shù)區(qū)間內(nèi)的所有成員。
ZREVRANGE key start stop [WITHSCORES] 返回有序集中指定區(qū)間內(nèi)的成員,通過索引,分?jǐn)?shù)從高到低。
ZREVRANGEBYSCORE key max min [WITHSCORES] 返回有序集中指定分?jǐn)?shù)區(qū)間內(nèi)的成員,分?jǐn)?shù)從高到低排序。
ZREVRANK key member 返回有序集合中指定成員的排名,有序集成員按分?jǐn)?shù)值遞減(從大到小)排序。
ZSCORE key member 返回有序集中,指定成員的分?jǐn)?shù)值。
ZUNIONSTORE destination numkeys key [key ...] 求兩個(gè)或多個(gè)有序集合的并集,并將返回結(jié)果存儲(chǔ)在新的 key 中。
ZSCAN key cursor [MATCH pattern] [COUNT count] 迭代有序集合中的元素(包括元素成員和元素分值)。

基本命令演示

下面通過一組命令,讓我們熟悉如何操作 zset 數(shù)據(jù)類型。以下示例是一個(gè)保存了員工薪水的有序集合:

#在有序集合中添加一個(gè)成員
127.0.0.1:6379> ZADD salary 4000 lucy
(integer) 1
#同時(shí)添加多個(gè)成員
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)計(jì)指定工資范圍內(nèi)的元素個(gè)數(shù)3000<=score<=5000
127.0.0.1:6379> ZCOUNT salary 3000 5000
(integer) 3
#表示3000 ZCOUNT salary (3000 (5000
(integer) 1
#返回指定工資范圍內(nèi)的score和成員,限制條件是跳過1個(gè)元素,返回2個(gè)元素。
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

在線練習(xí)工具:https://try.redis.io/

查看更多命令:https://redis.io/commands


分享題目:Rediszset有序集合(底層原理+圖解)
標(biāo)題鏈接:http://www.dlmjj.cn/article/coghhep.html