激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

Mysql|Sql Server|Oracle|Redis|MongoDB|PostgreSQL|Sqlite|DB2|mariadb|Access|數(shù)據(jù)庫(kù)技術(shù)|

服務(wù)器之家 - 數(shù)據(jù)庫(kù) - Redis - 利用Redis的有序集合實(shí)現(xiàn)排行榜功能實(shí)例代碼

利用Redis的有序集合實(shí)現(xiàn)排行榜功能實(shí)例代碼

2019-11-22 19:30justudy Redis

這篇文章主要給大家介紹了關(guān)于如何利用Redis的有序集合實(shí)現(xiàn)排行榜功能的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用Redis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

游戲中存在各種各樣的排行榜,比如玩家的等級(jí)排名、分?jǐn)?shù)排名等。玩家在排行榜中的名次是其實(shí)力的象征,位于榜單前列的玩家在虛擬世界中擁有無(wú)尚榮耀,所以名次也就成了核心玩家的追求目標(biāo)。

一個(gè)典型的游戲排行榜包括以下常見(jiàn)功能:

  1. 能夠記錄每個(gè)玩家的分?jǐn)?shù);
  2. 能夠?qū)ν婕业姆謹(jǐn)?shù)進(jìn)行更新;
  3. 能夠查詢每個(gè)玩家的分?jǐn)?shù)和名次;
  4. 能夠按名次查詢排名前N名的玩家;
  5. 能夠查詢排在指定玩家前后M名的玩家。

更進(jìn)一步,上面的操作都需要在短時(shí)間內(nèi)實(shí)時(shí)完成,這樣才能最大程度發(fā)揮排行榜的效用。

由于一個(gè)玩家名次上升x位將會(huì)引起x+1位玩家的名次發(fā)生變化(包括該玩家),如果采用傳統(tǒng)數(shù)據(jù)庫(kù)(比如MySQL)來(lái)實(shí)現(xiàn)排行榜,當(dāng)玩家人數(shù)較多時(shí),將會(huì)導(dǎo)致對(duì)數(shù)據(jù)庫(kù)的頻繁修改,性能得不到滿足,所以我們只能另想它法。

Redis作為NoSQL中的一員,近年來(lái)得到廣泛應(yīng)用。與Memcached相比,Redis擁有更多的數(shù)據(jù)類型和操作接口,具有更大的適用范圍,其中的有序集合(sorted set,也稱為zset)就非常適合于排行榜的構(gòu)建。下面簡(jiǎn)要總結(jié)一下。

1. Redis的安裝

Ubuntu下安裝Redis非常簡(jiǎn)單,執(zhí)行如下命令即可:

?
1
$ sudo apt-get install redis-server

安裝完畢,運(yùn)行命令行客戶端redis-cli就可以訪問(wèn)本地redis服務(wù)器。

?
1
2
$ redis-cli
redis 127.0.0.1:6379>

如果要使用最新版本,需要到Redis官網(wǎng)(redis.io)下載最新的代碼自行編譯,步驟略。

2. ZSet的常用命令

有序集合首先是集合,其成員(member)具有唯一性,其次,每個(gè)成員關(guān)聯(lián)了一個(gè)分?jǐn)?shù)(score),使得成員可以按照分?jǐn)?shù)排序。關(guān)于有序集合的介紹見(jiàn)redis.io/topics/data…,其命令見(jiàn)redis.io/commands#so…。

下面介紹幾個(gè)能用于排行榜的命令。

假設(shè)lb為排行榜名稱,user1、user2等為玩家唯一標(biāo)識(shí)。

1) zadd——設(shè)置玩家分?jǐn)?shù)

命令格式:zadd 排行榜名稱 分?jǐn)?shù) 玩家標(biāo)識(shí) 時(shí)間復(fù)雜度:O(log(N))

下面設(shè)置了4個(gè)玩家的分?jǐn)?shù),如果玩家分?jǐn)?shù)已經(jīng)存在,則會(huì)覆蓋之前的分?jǐn)?shù)。

?
1
2
3
4
5
6
7
8
redis 127.0.0.1:6379> zadd lb 89 user1
(integer) 1
redis 127.0.0.1:6379> zadd lb 95 user2
(integer) 1
redis 127.0.0.1:6379> zadd lb 95 user3
(integer) 1
redis 127.0.0.1:6379> zadd lb 90 user4
(integer) 1

2) zscore——查看玩家分?jǐn)?shù)

命令格式:zscore 排行榜名稱 玩家標(biāo)識(shí) 時(shí)間復(fù)雜度:O(1)
下面是查看user2這個(gè)玩家在lb排行榜中的分?jǐn)?shù)。

?
1
2
redis 127.0.0.1:6379> zscore lb user2
95

3) zrevrange——按名次查看排行榜

命令格式:zrevrange 排行榜名稱 起始位置 結(jié)束位置 [withscores] 時(shí)間復(fù)雜度:O(log(N)+M)

由于排行榜一般是按照分?jǐn)?shù)由高到低排序的,所以我們使用zrevrange,而命令zrange是按照分?jǐn)?shù)由低到高排序。

起始位置和結(jié)束位置都是以0開(kāi)始的索引,且都包含在內(nèi)。如果結(jié)束位置為-1則查看范圍為整個(gè)排行榜。

帶上withscores則會(huì)返回玩家分?jǐn)?shù)。

下面為查看所有玩家分?jǐn)?shù)。

?
1
2
3
4
5
6
7
8
9
10
redis 127.0.0.1:6379> zrevrange lb 0 -1 withscores
 
“user3”
“95”
“user2”
“95”
“user4”
“90”
“user1”
“89”

下面為查詢前三名玩家分?jǐn)?shù)。

?
1
2
3
4
5
6
7
8
redis 127.0.0.1:6379> zrevrange lb 0 2 withscores
 
“user3”
“95”
“user2”
“95”
“user4”
“90”

4) zrevrank——查看玩家的排名

命令格式:zrevrank 排行榜名稱 玩家標(biāo)識(shí) 時(shí)間復(fù)雜度:O(log(N))

與zrevrange類似,zrevrank是以分?jǐn)?shù)由高到低的排序返回玩家排名(實(shí)際返回的是以0開(kāi)始的索引),對(duì)應(yīng)的zrank則是以分?jǐn)?shù)由低到高的排序返回排名。

下面是查詢玩家user3和user4的排名。

?
1
2
3
4
redis 127.0.0.1:6379> zrevrank lb user3
(integer) 0
redis 127.0.0.1:6379> zrevrank lb user1
(integer) 3

5) zincrby——增減玩家分?jǐn)?shù)

命令格式:zincrby 排行榜名稱 分?jǐn)?shù)增量 玩家標(biāo)識(shí) 時(shí)間復(fù)雜度:O(log(N))

有的排行榜是在變更時(shí)重新設(shè)置玩家的分?jǐn)?shù),而還有的排行榜則是以增量方式修改玩家分?jǐn)?shù),增量可正可負(fù)。如果執(zhí)行zincrby時(shí)玩家尚不在排行榜中,則認(rèn)為其原始分?jǐn)?shù)為0,相當(dāng)于執(zhí)行zdd。

下面將user4的分?jǐn)?shù)增加6,使其名次上升到第一位。

?
1
2
3
4
5
6
7
8
9
10
11
12
redis 127.0.0.1:6379> zincrby lb 6 user4
“96”
redis 127.0.0.1:6379> zrevrange lb 0 -1 withscores
 
“user4”
“96”
“user3”
“95”
“user2”
“95”
“user1”
“89”

6) zrem——移除某個(gè)玩家

命令格式:zrem 排行榜名稱 玩家標(biāo)識(shí) 時(shí)間復(fù)雜度:O(log(N))

下面移除玩家user4。

?
1
2
3
4
5
6
7
8
9
10
redis 127.0.0.1:6379> zrem lb user4
(integer) 1
redis 127.0.0.1:6379> zrevrange lb 0 -1 withscores
 
“user3”
“95”
“user2”
“95”
“user1”
“89”

7) del——刪除排行榜

命令格式:del 排行榜名稱

排行榜對(duì)象在我們首次調(diào)用zadd或zincrby時(shí)被創(chuàng)建,當(dāng)我們要?jiǎng)h除它時(shí),調(diào)用redis通用的命令del即可。

?
1
2
3
4
redis 127.0.0.1:6379> del lb
(integer) 1
redis 127.0.0.1:6379> get lb
(nil)

3. 相同分?jǐn)?shù)問(wèn)題

免費(fèi)的方案總有那么一些不完美。從前面的例子我們可以看到,user2和user3具有相同的分?jǐn)?shù),但在按分?jǐn)?shù)逆序排序時(shí),user3排在了user2前面。而在實(shí)際應(yīng)用場(chǎng)景中,我們更希望看到user2排在user3前面,因?yàn)閡ser2比user3先加入排行榜,也就是說(shuō)user2先到達(dá)該分?jǐn)?shù)。

但Redis在遇到分?jǐn)?shù)相同時(shí)是按照集合成員自身的字典順序來(lái)排序,這里即是按照”user2″和”user3″這兩個(gè)字符串進(jìn)行排序,以逆序排序的話user3自然排到了前面。

要解決這個(gè)問(wèn)題,我們可以考慮在分?jǐn)?shù)中加入時(shí)間戳,計(jì)算公式為:

帶時(shí)間戳的分?jǐn)?shù) = 實(shí)際分?jǐn)?shù)*10000000000 + (9999999999 – timestamp)

timestamp我們采用系統(tǒng)提供的time()函數(shù),也就是1970年1月1日以來(lái)的秒數(shù),我們采用32位的時(shí)間戳(這能堅(jiān)持到2038年),由于32位時(shí)間戳是10位十進(jìn)制整數(shù)(最大值4294967295),所以我們讓時(shí)間戳占據(jù)低10位(十進(jìn)制整數(shù)),實(shí)際分?jǐn)?shù)則擴(kuò)大10^10倍,然后把兩部分相加的結(jié)果作為zset的分?jǐn)?shù)。考慮到要按時(shí)間倒序排列,所以時(shí)間戳這部分需要顛倒一下,這便是用9999999999減去時(shí)間戳的原因。當(dāng)我們要讀取玩家實(shí)際分?jǐn)?shù)時(shí),只需去掉后10位即可。

初步看起來(lái)這個(gè)方案還不錯(cuò),但這里面有兩個(gè)問(wèn)題。

第一個(gè)問(wèn)題是小問(wèn)題,采用秒為時(shí)間戳可能區(qū)分度還不夠,如果同一秒出現(xiàn)兩個(gè)分?jǐn)?shù)相同的仍然會(huì)出現(xiàn)前面的問(wèn)題,當(dāng)然我們可以選擇精度更高的時(shí)間戳,但在實(shí)際場(chǎng)景中,同一秒誰(shuí)排前面已經(jīng)無(wú)關(guān)緊要。

第二個(gè)問(wèn)題是大問(wèn)題,因?yàn)镽edis的分?jǐn)?shù)類型采用的是double,64位雙精度浮點(diǎn)數(shù)只有52位有效數(shù)字,它能精確表達(dá)的整數(shù)范圍為-2^53到2^53,最高只能表示16位十進(jìn)制整數(shù)(最大值為9007199254740992,其實(shí)連16位也不能完整表示)。這就是說(shuō),如果前面時(shí)間戳占了10位的話,分?jǐn)?shù)就只剩下6位了,這對(duì)于某些排行榜分?jǐn)?shù)來(lái)說(shuō)是不夠用的。我們可以考慮縮減時(shí)間戳位數(shù),比如從2015年1月1日開(kāi)始計(jì)時(shí),但這仍然增加不了幾位。或者減少區(qū)分度,以分鐘、小時(shí)來(lái)作為時(shí)間戳單位。

如果Redis的分?jǐn)?shù)類型為int64,我們就沒(méi)有上面的煩惱。說(shuō)到這里,其實(shí)Redis真應(yīng)該再額外提供一個(gè)int64類型的ZSet,但目前只能是幻想,除非自己改其源碼。

既然Redis也不能完美解決排行榜問(wèn)題,那最終是不是有必要自己實(shí)現(xiàn)一個(gè)專門(mén)的排行榜數(shù)據(jù)結(jié)構(gòu)呢?畢竟實(shí)際應(yīng)用中的排行榜有很多可以優(yōu)化的地方,比玩家呈金字塔分布,越是低分段玩家數(shù)量越多,同一分?jǐn)?shù)擁有大量玩家,玩家增加一分都可能超越很多玩家,這就為優(yōu)化提供了可能。

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)服務(wù)器之家的支持。

原文鏈接:https://juejin.im/post/5c876854f265da2d9e179112

延伸 · 閱讀

精彩推薦
  • RedisRedis全量復(fù)制與部分復(fù)制示例詳解

    Redis全量復(fù)制與部分復(fù)制示例詳解

    這篇文章主要給大家介紹了關(guān)于Redis全量復(fù)制與部分復(fù)制的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Redis爬蟲(chóng)具有一定的參考學(xué)習(xí)...

    豆子先生5052019-11-27
  • RedisRedis 事務(wù)知識(shí)點(diǎn)相關(guān)總結(jié)

    Redis 事務(wù)知識(shí)點(diǎn)相關(guān)總結(jié)

    這篇文章主要介紹了Redis 事務(wù)相關(guān)總結(jié),幫助大家更好的理解和學(xué)習(xí)使用Redis,感興趣的朋友可以了解下...

    AsiaYe8232021-07-28
  • Redisredis 交集、并集、差集的具體使用

    redis 交集、并集、差集的具體使用

    這篇文章主要介紹了redis 交集、并集、差集的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友...

    xiaojin21cen10152021-07-27
  • Redisredis中如何使用lua腳本讓你的靈活性提高5個(gè)逼格詳解

    redis中如何使用lua腳本讓你的靈活性提高5個(gè)逼格詳解

    這篇文章主要給大家介紹了關(guān)于redis中如何使用lua腳本讓你的靈活性提高5個(gè)逼格的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具...

    一線碼農(nóng)5812019-11-18
  • RedisRedis如何實(shí)現(xiàn)數(shù)據(jù)庫(kù)讀寫(xiě)分離詳解

    Redis如何實(shí)現(xiàn)數(shù)據(jù)庫(kù)讀寫(xiě)分離詳解

    Redis的主從架構(gòu),能幫助我們實(shí)現(xiàn)讀多,寫(xiě)少的情況,下面這篇文章主要給大家介紹了關(guān)于Redis如何實(shí)現(xiàn)數(shù)據(jù)庫(kù)讀寫(xiě)分離的相關(guān)資料,文中通過(guò)示例代碼介紹...

    羅兵漂流記6092019-11-11
  • Redis詳解Redis復(fù)制原理

    詳解Redis復(fù)制原理

    與大多數(shù)db一樣,Redis也提供了復(fù)制機(jī)制,以滿足故障恢復(fù)和負(fù)載均衡等需求。復(fù)制也是Redis高可用的基礎(chǔ),哨兵和集群都是建立在復(fù)制基礎(chǔ)上實(shí)現(xiàn)高可用的...

    李留廣10222021-08-09
  • RedisRedis的配置、啟動(dòng)、操作和關(guān)閉方法

    Redis的配置、啟動(dòng)、操作和關(guān)閉方法

    今天小編就為大家分享一篇Redis的配置、啟動(dòng)、操作和關(guān)閉方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧 ...

    大道化簡(jiǎn)5312019-11-14
  • Redisredis實(shí)現(xiàn)排行榜功能

    redis實(shí)現(xiàn)排行榜功能

    排行榜在很多地方都能使用到,redis的zset可以很方便地用來(lái)實(shí)現(xiàn)排行榜功能,本文就來(lái)簡(jiǎn)單的介紹一下如何使用,具有一定的參考價(jià)值,感興趣的小伙伴們...

    乘月歸5022021-08-05
主站蜘蛛池模板: 日本在线免费观看视频 | 免费1级做55爰片l在线观看 | 国产一区二区欧美精品 | 国产乱淫a∨片免费观看 | 亚洲午夜精品视频 | 91伊人久久 | 一区二区三区日韩 | 久久99国产精品久久99果冻传媒 | a免费毛片 | 久国产| 久草在线最新 | 亚洲啪啪 | 欧美成人三级大全 | 黄免费在线 | 免费国产一区二区视频 | 91免费在线播放 | 国产精品久久久久久久久久iiiii | 欧美a在线观看 | 国产成人精品免费视频大全办公室 | 日本68xxxx| 97视频| 91av亚洲 | 久久精品国产99国产精品澳门 | 91九色网址 | 国产麻豆交换夫妇 | 欧美成人精品一区二区男人小说 | 国产成人精品免费视频大全办公室 | av手机在线电影 | 黄色7777| arabxxxxvideos| 精品国产中文字幕 | 日韩精品中文字幕在线播放 | 国产91一区二区三区 | 黄在线免费 | 欧美日韩在线播放 | 久久久精品视频国产 | 久久久精彩| 成人一区二区在线观看视频 | 91久久久国产精品 | 综合毛片 | 综合毛片 |