使用Redis完成排行榜系統

redis里有一種很特殊的數據類型——有序集合。之前我們學過的集合的概念是,集合里所有元素都是唯一的、無序的。但這里怎么出現了有序集合,他是怎么來實現有序的呢?

有序集合里元素還是唯一的,但會給每個元素設置一個socre(分值),通過這個分值來實現有序的。如下圖所示:

使用Redis完成排行榜系統

有序集合API

下面介紹幾個有序集合的API,實現排行榜功能需要知道這些API的用法。

zAdd

我們想設置一個球員2k能力值的有序列表,使用球員名為元素,能力值為scores。

庫里的投射能力為100,詹姆斯為92,哈登為96,保羅為97

sadd一次可以添加1個或多個元素

127.0.0.1:6379[1]>?zadd?2kplayer:shoot?100?curry (integer)?1 127.0.0.1:6379[1]>?zadd?2kplayer:shoot?92?james?96?harden?97?paul (integer)?3

zIncrBy

這一個月來,哈登連續爆種,瘋狂連續砍高分,那么,2k決定將他的投射能力值提高2點

127.0.0.1:6379[1]>?zincrby?2kplayer:shoot?2?harden "98"

zRange、zRevRange

現在我們想知道能力值前3名的球員是哪3個。

127.0.0.1:6379[1]>?zrange?2kplayer:shoot?0?2?withscores 1)?"james" 2)?"92" 3)?"paul" 4)?"97" 5)?"harden" 6)?"98"

redis默認采用正序,分值從小到大排序。所以我們需要使用zRevRange

127.0.0.1:6379[1]>?zrevrange?2kplayer:shoot?0?2?withscores 1)?"curry" 2)?"100" 3)?"harden" 4)?"98" 5)?"paul" 6)?"97"

zUnionStore

2k能力值是有多方面的,投射只是其中一項,速度、上籃等都是能力值的一部分。

127.0.0.1:6379[1]>?zadd?2kplayer:speed?99?james?90?paul?90?curry?93?harden? (integer)?4

這時候,想知道球員綜合能力值的話,就需要將每一項的得分都加起來

127.0.0.1:6379[1]>?zunionstore?2kplayer?2?2kplayer:shoot?2kplayer:speed (integer)?4 127.0.0.1:6379[1]>?zrange?2kplayer?0?-1?withscores 1)?"paul" 2)?"187" 3)?"curry" 4)?"190" 5)?"harden" 6)?"191" 7)?"james" 8)?"191"

實現排行榜系統

場景如下:一個視頻點播系統,每天觀看的人很多。該系統有個榜單功能,展示觀看量最多的視頻。分為今日榜單、三日榜單、一周排行、月榜單。

思路:首先是按天統計視頻觀看次數,然后再統計出今日榜單、三日榜單等。

統計視頻觀看次數的偽代碼如下:

//?觀看視頻 function?view?($videoId) { ????$key?=?'video:view:'.date('Y-m-d');?? ?????? ????if?(!$redis->exists($key))?{ ????????$redis->zIncrBy($key,?1,?$videoId); ????????$redis->expire($key,?86400?*?30); ????} ???? ????$redis->zIncrBy($key,?1,?$videoId); }

今日最熱

今日最熱有一個注意點,當新的一天剛開始時,數據可能為空或很少。所以,我們可以將今日和昨日的數據合并起來,但將今日的數據權重設高些。

今日最熱功能實現偽代碼如下:

function?todayHot?() { ????$tokeyKey?=?'video:view:'.date('Y_m_d'); ????$yesKey?=?'video:view:'.?date('Y_m_d',?time()?-?86400); ????$keyUnion?=?"view:rank:today"; ???? ????$redis->zUnionStore($keyUnion,?[$tokeyKey,?$yesKey],?[10,?1]); ????//?取前100名 ????return?$redis->zRevRange($keyUnion,?0,?99); }

三日榜單

function?threeHot?() { ????$keyUnion?=?'view:rank:three'; ????$unionKeys?=?[]; ???? ????for?($i=0;?$i?zUnionStore($keyUnion,?$unionKeys); ????return?$redis->zRevRange($keyUnion,?0,?99,?true); }

周榜單、月榜單等和三日榜單的思路完成一樣,所以就不貼出代碼了。

? 版權聲明
THE END
喜歡就支持一下吧
點贊15 分享