2.6依啰、有序集合

有序集合

有序集合相對(duì)于哈希、列表店枣、集合來說會(huì)有一點(diǎn)點(diǎn)陌生速警,但既然叫有序集合,那么它
和集合必然有著聯(lián)系鸯两,它保留了集合不能有重復(fù)成員的特性闷旧,但不同的是,有序集合
中的元素可以排序钧唐。但是它和列表使用索引下標(biāo)作為排序依據(jù)不同的是忙灼,他給每個(gè)元
素設(shè)置一個(gè)分?jǐn)?shù)(score)作為排序的依據(jù)。下表為有序集合user:ranking钝侠,其中包
含kris该园、mike、frank帅韧、tim里初、martin、tom忽舟,他們的分?jǐn)?shù)分別是1双妨、91叮阅、200刁品、
220、250哑诊、251,有序集合提供了獲取指定分?jǐn)?shù)和元素范圍查詢暑劝、計(jì)算成員排名等功
能,合理的使用有序集合傅联,能幫助我們?cè)趯?shí)際開發(fā)中解決很多問題先改。

score member
1 kris
91 mike
200 frank
220 tim
250 martin
251 tom

開發(fā)提示:有序集合中的元素不能重復(fù),但是score可以重復(fù)
下表給出列表蒸走、集合仇奶、有序集合三者的異同點(diǎn):

數(shù)據(jù)結(jié)構(gòu) 是否允許重復(fù)元素 是否有序 有序?qū)崿F(xiàn)方式 應(yīng)用場(chǎng)景
列表 索引下標(biāo) 時(shí)間軸、消息隊(duì)列等
集合 標(biāo)簽比驻、社交等
有序集合 分值 排行榜系統(tǒng)该溯、社交等
  1. 命令

    1. 集合內(nèi)
    • 添加成員

      zadd key score member [score member]

      下面操作向有序集合user:ranking添加用戶tom和他的分?jǐn)?shù)251:

      127.0.0.1:6379> zadd user:ranking 251 tom
      (integer) 1
      

      返回結(jié)果代表成功添加成員的個(gè)數(shù):

      127.0.0.1:6379> zadd user:ranking 1 kris 91 mike 200 frank 220 tim 250 martin
      (integer) 5
      

      有關(guān)zadd命令有兩點(diǎn)需要注意:

      • Redis3.2位zadd命令添加了nx、xx别惦、ch狈茉、incr四個(gè)選項(xiàng):

        • nx:member必須不存在,才可以設(shè)置成功掸掸,用于添加氯庆。
        • xx:member必須存在,才可以設(shè)置成功猾漫,用于更新点晴。
        • ch:返回此次操作后,有序集合元素和分?jǐn)?shù)發(fā)生變化的個(gè)數(shù)悯周。
        • incr:對(duì)score做增加,相當(dāng)于后面介紹的zincrby陪竿。
      • 有集合相比集合提供了排序字段禽翼,但是也產(chǎn)生了代價(jià),zadd的時(shí)間復(fù)雜度為O(log(n)),sadd的時(shí)間復(fù)雜度為O(1)族跛。

    • 計(jì)算成員個(gè)數(shù)

      zcard key

      例如下面操作返回有序集合user:ranking的成員數(shù)為5闰挡,和集合類型的
      scard命令一樣,zcard的時(shí)間復(fù)雜度為O(1).

      127.0.0.1:6379> zcard user:ranking
      (integer) 5
      
    • 計(jì)算某個(gè)成員的分?jǐn)?shù)

      zscore key member

      tom的分?jǐn)?shù)為251礁哄,如果成員不存在則返回nil:

      127.0.0.1:6379> zscore user:ranking tom
      "251"
      127.0.0.1:6379> zscore user:ranking test
      (nil)
      
    • 計(jì)算成員的排名

      zrank key member

      zrevrank key member

      zrank是從分?jǐn)?shù)從低到高返回排名长酗,zrevrank反之。例如下面操作中桐绒,tom
      在zrank和zrevrank分別排名第5名和第0(排名從0開始計(jì)算)夺脾。

      127.0.0.1:6379> zrank user:ranking tom
      (integer) 5
      127.0.0.1:6379> zrevrank user:ranking tom
      (integer) 0
      
    • 刪除成員

      zrem key member [member ...]

      下面操作將成員mike從有序集合user:ranking中刪除。

      127.0.0.1:6379> zrem user:ranking mike 
      (integer) 1
      

      返回結(jié)果為成功刪除的個(gè)數(shù)茉继。

    • 增加成員的分?jǐn)?shù)

      zincrby key increment member

      下面操作給tom增加了9分咧叭,分?jǐn)?shù)變?yōu)榱?60分:

      127.0.0.1:6379> zincrby user:ranking 9 tom
      "260"
      
    • 返回指定排名范圍的成員

      zrange key start end [withscores]

      zrevrange key start end [withscores]

      有序集合是按照分值排名的,zrange是從低到高返回烁竭,zrevrange反之菲茬。
      下面代碼排名最低的是三個(gè)成員,如果加上withscores選項(xiàng),同時(shí)會(huì)返回
      成員的分?jǐn)?shù):

      127.0.0.1:6379> zrange user:ranking 0 2 withscores
      1) "kris"
      2) "1"
      3) "frank"
      4) "200"
      5) "tim"
      6) "220"
      127.0.0.1:6379> 
      1) "tom"
      2) "260"
      3) "martin"
      4) "250"
      5) "tim"
      6) "220"
      
    • 返回指定分?jǐn)?shù)范圍的成員

      zrangebyscore key min max [withscores] [limit offset count]

      zrevrangebyscore key max min [withsocre] [limit offset count]

      其中zrangebyscore按照分?jǐn)?shù)從低到高返回婉弹,zrevrangebyscore反之睬魂。例
      如下面操作從低到高返回200到221分的成員,withscores現(xiàn)象會(huì)同時(shí)返回
      每個(gè)成員的分?jǐn)?shù)镀赌。[limit offset count]選項(xiàng)可以限制輸出的其實(shí)位置
      和個(gè)數(shù):

      127.0.0.1:6379> zrangebyscore user:ranking 200 221 withscore
      1) "frank"
      2) "200"
      3) "tim"
      4) "220"
      127.0.0.1:6379> zrevrangebyscore user:ranking 200 221 withscores
      1) "tim"
      2) "220"
      3) "frank"
      4) "200"
      
    • 返回指定分?jǐn)?shù)范圍成員個(gè)數(shù)

      zcount key min max

      下面操作返回200到221分的成員的個(gè)數(shù):

      127.0.0.1:6379> zcount user:ranking 221 200
      (integer) 2
      
    • 刪除指定排名內(nèi)的升序元素

      zremrangebyrank key start end

      下面操作刪除第start到第end名的成員:

      127.0.0.1:6379> zremrangebyrank user:ranking 0 2
      (integer) 3
      
    • 刪除指定分?jǐn)?shù)范圍的成員

      zremrangebyscore key min max

      下面操作將250分以上的成員全部刪除汉买,返回結(jié)果為成功刪除的個(gè)數(shù):

      127.0.0.1:6379> zremrangebyscore user:ranking (250 +inf
      (integer) 2
      
    1. 集合間操作

    下表為有序集合user:ranking:1

    score member
    1 kris
    91 mike
    200 frank
    220 tim
    250 martin
    251 tom

    下表為有序集合user:ranking:2

    score member
    8 james
    77 mike
    625 martin
    888 tom
    127.0.0.1:6379> zadd user:ranking:1 1 kris 91 mike 200 frank 220 tim 250 martin 251 tom
    (integer) 6
    127.0.0.1:6379> zadd user:ranking:2 8 james 77 mike 625 martin 888 tom
    (integer) 4
    
    • 交集

      zinterstore destination numkeys key [key ...] [weights weight [weight ...]] [aggregate sum|min|max]

      這個(gè)命令參數(shù)較多,下面分別進(jìn)行說明:

      • destination:交集計(jì)算結(jié)果保存到這個(gè)鍵佩脊。
      • numkeys:需要做交集計(jì)算鍵的個(gè)數(shù)蛙粘。
      • key [key ...]:需要做交集計(jì)算的鍵。
      • weights weight [weight ...]:每個(gè)鍵的權(quán)重威彰,在做交集計(jì)算式出牧,每個(gè)鍵中的每個(gè)member會(huì)將自己分?jǐn)?shù)乘以這個(gè)權(quán)重,每個(gè)鍵的權(quán)重默認(rèn)是1.
      • aggregate sum|min|max:計(jì)算成員交集后歇盼,分值可以按照sum(和)舔痕、min(最小值)、max(最大值)做匯總豹缀,默認(rèn)值是sum伯复。

      下面操作對(duì)user:ranking:1和user:ranking:2做交集,weights和
      aggregate使用了默認(rèn)配置邢笙,可以看到目標(biāo)鍵user:ranking:1_inter_2
      對(duì)分值做了sum操作:

      127.0.0.1:6379> zinteerstore user:ranking:1_inter_2 2 user:ranking:1 user:ranking:2
      (integer) 3
      127.0.0.1:6379> zrange user:ranking:1_inter_2 0 -1 withscores
      1) "mike"
      2) "168"
      3) "martin"
      4) "875"
      5) "tom"
      6) "1139"
      

      如果想讓user:ranking:2的權(quán)重變?yōu)?.5啸如,并且聚合效果使用max,可以
      執(zhí)行如下操作:

      127.0.0.1:6379> zinterstore user:ranking:1_inter_2 2 user:ranking:1 user:ranking 2 weights 1 0.5 aggregate max
      (integer) 3
      127.0.0.1:6379> zrange user:ranking:1_inter_2 0 -1 withscores
      1) "mike"
      2) "91"
      3) "martin"
      4) "312.5"
      5) "tom"
      6) "444"
      
    • 并集

      zunionstore destination numkeys key [key ...] [weights weight [weight ...]] [aggregate sum|min|max]

      該命令的所有參數(shù)和zinterstore是一致的氮惯,只不過是做并集計(jì)算叮雳,例如
      下面操作是計(jì)算user:ranking:1和user:ranking:2的并集,weights和
      aggregate使用了默認(rèn)配置妇汗,可以看到目標(biāo)鍵user:ranking:1_union_2
      對(duì)分值做了sum操作:

      127.0.0.1:6379> zunionstore user:ranking:1_union_2 2 user:ranking:1 user:ranking:2
      (integer) 7
      127.0.0.1:6379> zrange user:ranking:1_union_2 0 -1 withscores
      1) "kris"
      2) "1"
      3) "james"
      4) "8"
      5) "mike"
      6) "168"
      7) "frank"
      8) "200"
      9) "tim"
      10) "220"
      11) "martin"
      12) "875"
      13) "tom"
      14) "1139"
      

    下表為這些命令的時(shí)間復(fù)雜度:

    命令 時(shí)間復(fù)雜度
    zadd key score member [score member ...] O(k*log(n)),k是添加成員的個(gè)數(shù)帘不,n是當(dāng)前有序集合成員個(gè)數(shù)
    zcard key O(1)
    zscore key member O(1)
    zrank key member O(log(n)),n是當(dāng)前有序集合成員個(gè)數(shù)
    zrevrank key member O(log(n)),n是當(dāng)前有序集合成員個(gè)數(shù)
    zrem key member [member ...] O(k*log(n)),k是添加成員的個(gè)數(shù),n是當(dāng)前有序集合成員個(gè)數(shù)
    zincrby key increment member O(log(n)),n是當(dāng)前有序集合成員個(gè)數(shù)
    zrange key start end [withscores] O(log(n) + k),k是要獲取的成員個(gè)數(shù)杨箭,n是當(dāng)前有序集合成員個(gè)數(shù)
    zrevrange key start end [withscores] O(log(n) + k),k是要獲取的成員個(gè)數(shù)寞焙,n是當(dāng)前有序集合成員個(gè)數(shù)
    zrangebysocre key min max [withscores] O(log(n) + k),k是要獲取的成員個(gè)數(shù),n是當(dāng)前有序集合成員個(gè)數(shù)
    zrevrangebyscore key max min [withscores] O(log(n) + k),k是要獲取的成員個(gè)數(shù)互婿,n是當(dāng)前有序集合成員個(gè)數(shù)
    zcount O(log(n)),n是當(dāng)前有序集合成員個(gè)數(shù)
    zremrangebyrank key start end O(log(n) + k),k是要?jiǎng)h除的成員個(gè)數(shù)捣郊,n是當(dāng)前有序集合成員個(gè)數(shù)
    zremrangebyscore key min max O(log(n) + k),k是要?jiǎng)h除的成員個(gè)數(shù),n是當(dāng)前有序集合成員個(gè)數(shù)
    zinterstore destination numkeys key [key ...] O(n*k) + O(m * log(m)),n是成員數(shù)最小的有序集合成員個(gè)數(shù)擒悬,k是有序集合的個(gè)數(shù)模她,m是結(jié)果集中成員個(gè)數(shù)

    zunionstore destination numkeys key [key ...]O(n*k) + O(m * log(m)),n是成員數(shù)最小的有序集合成員個(gè)數(shù),k是有序集合的個(gè)數(shù)懂牧,m是結(jié)果集中成員個(gè)數(shù)

  2. 內(nèi)部編碼

    有序結(jié)合類型的內(nèi)部編碼有兩種:

    • ziplist(壓縮列表):當(dāng)有序集合的元素個(gè)數(shù)小于
      zset-max-ziplist-entries配置(默認(rèn)128個(gè))侈净,同時(shí)每個(gè)元素的值都小于
      zset-max-ziplist-value配置(默認(rèn)64字節(jié))時(shí)尊勿,Redis會(huì)用ziplist來作為
      有序集合的內(nèi)部實(shí)現(xiàn),ziplist可以有效減少內(nèi)存的使用畜侦。

    • skiplist(跳躍表):當(dāng)ziplist條件不滿足是元扔,有序結(jié)合會(huì)使用skiplist
      作為內(nèi)部實(shí)現(xiàn),因?yàn)榇藭r(shí)ziplist的讀寫效率會(huì)下降旋膳。

    下面用實(shí)例來說明:

    1)當(dāng)元素個(gè)數(shù)較少且每個(gè)元素較小時(shí)澎语,內(nèi)部編碼為ziplist:

    127.0.0.1:6379> zadd zsetkey 50 e1 60 e2 30 e3
    (integer) 3
    127.0.0.1:6379> object encoding zsetkey
    "ziplist"
    

    2.1)當(dāng)元素超過128個(gè),內(nèi)部編碼變?yōu)閟kiplist:

    127.0.0.1:6379> zadd zsetkey 50 e1 60 e2 30 e3 12 e4 ...忽略... 84 e 129
    (integer) 129
    127.0.0.1:6379> object encoding zsetkey
    "skiplist"
    

    2.2)當(dāng)某個(gè)元素大于64字節(jié)是验懊,內(nèi)部編碼也會(huì)變?yōu)閟kiplist:

    127.0.0.1:6379> zadd zsetkey 20 "one string is bigger than 64 byte..."
    (integer) 1
    127.0.0.1:6379> object encoding zsetkey
    "skiplist"
    
  3. 使用場(chǎng)景

    有序結(jié)合比較典型的使用場(chǎng)景就是排行榜系統(tǒng)擅羞。例如視頻網(wǎng)站需要對(duì)用戶上傳的
    視頻做排行榜,榜單的維度可能是多個(gè)方面的:按照時(shí)間义图、按照播放數(shù)量减俏、按照
    獲得的贊數(shù)。本節(jié)使用在贊數(shù)這個(gè)維度碱工,記錄每天用戶上傳視頻的排行榜娃承。主要
    需要實(shí)現(xiàn)以下4個(gè)功能。

    (1)添加用戶贊數(shù)

    例如用戶mike上傳了一個(gè)視頻怕篷,并獲得了3個(gè)贊历筝,可以使用有序集合的zadd
    和zincrby功能:

     `zad user:ranking:2016_03_15 3 mike`
    

    如果之后再獲得一個(gè)贊,可以使用zincrby:

     `zincrby user:ranking:2016_03_15 1 mike`
    

    (2)取消用戶在贊數(shù)

    由于各種原因(例如用戶注銷廊谓、用戶作弊)需要將用戶刪除梳猪,此時(shí)需要將
    用戶從榜單中刪除掉,可以使用zrem蹂析。例如刪除成員tom:

     `zrem user:ranking:2016_03_15 tom`
    

    (3)展示獲取贊數(shù)最多的十個(gè)用戶

    此功能使用zrevrange命令實(shí)現(xiàn):

     `zrevrangebyrank user:rankin:2016_03_15 0 9`
    

    (4)展示用戶信息以及用戶分?jǐn)?shù)

    此功能將用戶名作為鍵后綴舔示,將用戶信息保存在哈希類型中,至于用戶的
    分?jǐn)?shù)和排名可以使用zsore和zrank兩個(gè)功能:

     `hgetall user:info:tom`
    
     `zsocre user:ranking:2016_03_15 mike`
    
     `zrank user:ranking:2016_03_15 mike`
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末电抚,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子竖共,更是在濱河造成了極大的恐慌蝙叛,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件公给,死亡現(xiàn)場(chǎng)離奇詭異借帘,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)淌铐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門肺然,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人腿准,你說我怎么就攤上這事际起∈奥担” “怎么了?”我有些...
    開封第一講書人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵街望,是天一觀的道長校翔。 經(jīng)常有香客問我,道長灾前,這世上最難降的妖魔是什么防症? 我笑而不...
    開封第一講書人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮哎甲,結(jié)果婚禮上蔫敲,老公的妹妹穿的比我還像新娘。我一直安慰自己炭玫,他們只是感情好奈嘿,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著础嫡,像睡著了一般指么。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上榴鼎,一...
    開封第一講書人閱讀 51,727評(píng)論 1 305
  • 那天伯诬,我揣著相機(jī)與錄音,去河邊找鬼巫财。 笑死盗似,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的平项。 我是一名探鬼主播赫舒,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼闽瓢!你這毒婦竟也來了接癌?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤扣讼,失蹤者是張志新(化名)和其女友劉穎缺猛,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體椭符,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡荔燎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了销钝。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片有咨。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蒸健,靈堂內(nèi)的尸體忽然破棺而出座享,到底是詐尸還是另有隱情婉商,我是刑警寧澤,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布征讲,位于F島的核電站据某,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏诗箍。R本人自食惡果不足惜癣籽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望滤祖。 院中可真熱鬧筷狼,春花似錦、人聲如沸匠童。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽汤求。三九已至俏险,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間扬绪,已是汗流浹背竖独。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留挤牛,地道東北人莹痢。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像墓赴,于是被迫代替她去往敵國和親竞膳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • redis是一個(gè)以key-value存儲(chǔ)的非關(guān)系型數(shù)據(jù)庫诫硕。有五種數(shù)據(jù)類型坦辟,string、hashes章办、list长窄、s...
    林ze宏閱讀 996評(píng)論 0 0
  • 1 Redis介紹1.1 什么是NoSql為了解決高并發(fā)、高可擴(kuò)展疮绷、高可用翰舌、大數(shù)據(jù)存儲(chǔ)問題而產(chǎn)生的數(shù)據(jù)庫解決方...
    克魯?shù)吕?/span>閱讀 5,296評(píng)論 0 36
  • 集合 集合(set)類型也是用來保存多個(gè)的字符串元素椅贱,但和列表類型不一樣的是懂算,集合中不允許有重復(fù)元素,并且集合中的...
    linuxzw閱讀 445評(píng)論 0 4
  • 一庇麦、Redis基礎(chǔ) 1.概述 Redis是一個(gè)開源计技,高級(jí)的鍵值存儲(chǔ)和一個(gè)適用的解決方案,用于構(gòu)建高性能山橄,可擴(kuò)展的W...
    鄭元吉閱讀 301評(píng)論 0 0
  • 人臉識(shí)別近來可以說是非常的熱門垮媒,無論是iphonex的faceid人臉解鎖、faceID支付等等航棱,還是各種安防監(jiān)控...
    daiw閱讀 16,404評(píng)論 1 2