redis(二、實現(xiàn)投票功能)

寫在前面的話:最近出于提升自己技術(shù)能力的考慮,準備系統(tǒng)的學(xué)習(xí)一下redis。這里主要是一個記錄收獲以及摘錄干貨的作用。學(xué)習(xí)書籍為《redis 實戰(zhàn)》。不感興趣的戰(zhàn)友不必勉強閱讀。

現(xiàn)在很多的網(wǎng)站,比如簡書,都有提供對文章進行點贊等投票性質(zhì)的功能。某種場景下,網(wǎng)站會根據(jù)文章的發(fā)布時間以及文章獲得的投票數(shù)量來計算出一個評分,然后根據(jù)這個評分來決定如何排序和展示文章。而要構(gòu)建一個這樣的文章投票網(wǎng)站,我們首先要做的就是為這個網(wǎng)站設(shè)置一些數(shù)值和限制條件:如果一篇文章獲得了超過200張投票,那么網(wǎng)站就認為這是一篇值得推薦的文章;假如網(wǎng)站每天有1000篇文章發(fā)布,而有50篇文章達到了這個要求,那么網(wǎng)站會把這50篇文章放到文章列表的前100位至少一天。

為了產(chǎn)生一個能夠隨著時間流逝不斷減少的評分,程序需要根據(jù)文章的發(fā)表時間和當(dāng)前的時間來計算評分。具體做法是: 將文章得到的投票數(shù)乘以一個常量,再加上文章的發(fā)布時間,得到的結(jié)果即為評分。在這里我們將常量設(shè)為432.因為一天為86400秒,投票的門檻數(shù)是200,它們的比值即為432.這樣的話,文章每獲得一張投票,評分即增加432分。我們除了計算文章的評分之外,還要使用redis來有序的存儲網(wǎng)站文章的各種信息。在這里,對于每篇文章,我們使用散列(hash)來存儲它的標題,發(fā)表時間,作者,文章url,以及獲得的投票數(shù)等。另外,正對網(wǎng)站的所有文章,我們還需要兩個有序集合(zset)來存儲文章:第一個有序集合,成員為文章ID,分值為發(fā)布時間;而第二個有序集合成員同樣為文章ID,但是分值為文章的評分。這樣的話,網(wǎng)站既可以按照發(fā)布時間的先后來展示文章,也可以按照文章的評分(受歡迎程度)來展示文章。

為了防止重復(fù)投票,我們還要為每篇文章記錄一個已投票用戶的名單。所以,程序?qū)槊科恼聞?chuàng)建一個集合,用來存儲已投票用戶的ID,為了 解決內(nèi)存,我們還應(yīng)當(dāng)規(guī)定,當(dāng)一篇文章發(fā)布超過一個月(或者你認為的合適的時間長度),用戶將不能再對文章進行投票。同時文章評分將被固定,而記錄文章已投票用戶名單的集合也就可以刪除了。

ok,到了這里我們的準備工作就已經(jīng)做好了。接下來就是具體利用redis的各類函數(shù)去實現(xiàn)投票的功能了。當(dāng)然這里主要是寫思路。做程序的本質(zhì)就是用代碼把你的想法給實現(xiàn)出來。所謂的程序有bug,無非就是你考慮的問題不全面,當(dāng)系統(tǒng)面對你沒有預(yù)設(shè)好處理方案的問題時,就會報錯。

投票

當(dāng)用戶嘗試對某篇文章進行投票時,程序會先使用zscore命令去檢查記錄這篇文章發(fā)布時間的有序集合,如果未超過一個月,那么程序?qū)⑹褂胹add命令將用戶添加到記錄這篇文章已投票用戶名單的集合里。如果添加操作成功,說明這個用戶是第一個給這篇文章投票,系統(tǒng)會繼續(xù)使用Zincrby命令為這篇文章評分增加432評分;并使用Hincrby命令對在散列(hash)中記錄的文章投票數(shù)進行自增+1。在這一系列的操作里,為了保證數(shù)據(jù)的一致性,sadd,zincrby,hincrby三個命令是需要放到一個事務(wù)里的。

發(fā)布文章

發(fā)布文章需要先創(chuàng)建一個文章ID,這項工作可以通過對一個計數(shù)器進行自增為1的操作來實現(xiàn)。接著程序需要使用sadd命令將文章發(fā)布者的ID添加到記錄這篇文章已投票用戶的集合里(是的,每篇文章默認作者會給自己投一票~),并使用expire命令為這個集合設(shè)置一個過期時間,讓redis可以在到期后自動刪除這個集合。之后,系統(tǒng)還需要調(diào)用Hmset命令來存儲文章的相關(guān)詳情信息,并執(zhí)行兩個Zadd命令,將文章的初識評分和發(fā)布時間分別存到兩個有序集合里。這樣,文章的發(fā)布就實現(xiàn)了。

排序文章

那么接下來就要考慮怎樣取出評分最高的文章或者最新發(fā)表的文章了。為實現(xiàn)這兩個功能,系統(tǒng)需要先使用ZREVRANGE命令取出多個文章ID,然后再對每個ID執(zhí)行一次HGETALL命令來取出文章的詳情。然后根據(jù)詳情里的評分數(shù)值或者發(fā)布時間,我們就可以獲得評分最高或者最新發(fā)布的文章。需要特別注意的是,有序集合會根據(jù)成員的分值從小到大去排列元素,所以要使用ZREVRANGE命令,以‘從大到小’的排列順序來取數(shù)據(jù)才是正確的做法。

文章分組

另外一個非常實用的功能是文章分類顯示。這個功能可以讓用戶只看到與特定話題相關(guān)的文章。群組功能有兩個部分組成,一個部分負責(zé)記錄文章屬于哪個群組,另一個負責(zé)取出群組里的文章。為了記錄各個群組都保存了哪些文章,網(wǎng)站需要為每個群組都創(chuàng)建一個集合,并將所有屬于同一群組的文章ID都記錄在群組里。而為了能夠根據(jù)評分對群組文章進行排序和分頁,所有的文章也要按照分值大小有序的存到一個有序集合里。redis的ZINTERSTORE命令可以接受多個集合和多個有序集合作為輸入,然后找出他們的交集。并合并成員的分值(所有的集合成員的分值默認為1),最后以合并后的成員分值進行排序。這樣,通過對存儲群組文章的集合和存儲文章評分的有序集合執(zhí)行ZINTERSTORE命令,我們可以得到按照文章評分排序的文章群組;而通過對存儲群組文章的集合和存儲文章發(fā)表時間的有序執(zhí)行ZINTERSTORE命令,我們可以得到按照文章發(fā)表時間排序的文章群組?!咀⒁猓寒?dāng)群組較大時,執(zhí)行ZINTERSTORE命令會較費時。為了減少redis的工作量,可以考慮加上緩存。每次系統(tǒng)嘗試去計算交集結(jié)果時,可以先去緩存中拿數(shù)據(jù)】

感悟:在學(xué)習(xí)redis時,還是要先自我屏蔽一下之前使用關(guān)系型數(shù)據(jù)庫時的固化思維。然后深刻理解redis的五種數(shù)據(jù)類型的特點,才能真正上手redis。沒有人可以在第一時間就把代碼寫的非常健壯??偸且S著業(yè)務(wù)場景的復(fù)雜而去迭代我們的函數(shù)。但是經(jīng)驗可以解決九成以上的bug,所以,代碼還是要多敲,大咖們的代碼也是要多去閱讀。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,825評論 25 709
  • 當(dāng)然孤單,是值得享受的孤單 國慶假期,一個人去了一趟山東,煙臺和威海兩座城市。去山東,自然是為了看海,但是旅游(或...
    桃籽霽閱讀 774評論 2 4
  • 在政治課本上看到那么一句話,“宏觀物體是機械運動的載體”,看起來與你毫無關(guān)聯(lián),我卻不可避免地想起了你。 窗外的...
    小北姐姐閱讀 242評論 0 0
  • 作為2016級的大一新生,第一堂課就是避之不及的軍訓(xùn)。 我在廈門。曾經(jīng)的一條“你若軍訓(xùn),便是晴天”的亙古不變的...
    epinghong閱讀 208評論 0 0
  • 文/喵先生 愛上一只貓 喜歡她柔順的毛發(fā) 勻稱標致的身材 最美麗的是 那雙不羈的眼眸 我們同在風(fēng)雨中長大 每日為我...
    袁豪杰閱讀 174評論 0 0

友情鏈接更多精彩內(nèi)容