成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Python--Redis實(shí)戰(zhàn):第一章:初識(shí)Redis:第三節(jié):你好Redis-文章投票試煉

Meils / 2609人閱讀

摘要:為了防止用戶對(duì)同一篇文章進(jìn)行多次投票,網(wǎng)站需要為每一篇文章記錄一個(gè)已投票用戶名單。上一篇文章實(shí)戰(zhàn)第一章初識(shí)第二節(jié)數(shù)據(jù)結(jié)構(gòu)簡(jiǎn)介下一篇文章實(shí)戰(zhàn)第二章使用構(gòu)建應(yīng)用第一節(jié)登錄和緩存

上一篇文章: Python--Redis實(shí)戰(zhàn):第一章:初識(shí)Redis:第二節(jié):Redis數(shù)據(jù)結(jié)構(gòu)簡(jiǎn)介
下一篇文章:Python--Redis實(shí)戰(zhàn):第二章:使用Redis構(gòu)建Web應(yīng)用:第一節(jié):登錄和cookie緩存

在對(duì)Redis提供的5種結(jié)構(gòu)有了基本的了解后,現(xiàn)在是時(shí)候來學(xué)習(xí)一下怎樣使用這些結(jié)構(gòu)來解決實(shí)際問題了。

最近幾年,越來越多的網(wǎng)站開始提供對(duì)網(wǎng)頁鏈接、文章或者穩(wěn)贏進(jìn)行投票的功能,這些網(wǎng)站會(huì)根據(jù)文章的發(fā)布時(shí)間和文章獲得的投票數(shù)量計(jì)算出一個(gè)評(píng)分,然后根據(jù)這個(gè)評(píng)分來決定如何排序和展示文章。

本節(jié)將展示如何使用Redis來構(gòu)建一個(gè)簡(jiǎn)單的文章投票網(wǎng)站的后端。

1、對(duì)文章進(jìn)行投票

要構(gòu)建一個(gè)文章投票網(wǎng)站,我們首先要做的就是為了這個(gè)網(wǎng)站設(shè)置一些數(shù)值和限制條件:如果一篇文章獲得了至少200張支持票,那么久認(rèn)為這篇文章是【有趣的】。假如這個(gè)網(wǎng)站每天發(fā)布1000篇文章,而其中的50篇符合網(wǎng)站對(duì)【有趣】文章的要求,那么網(wǎng)站要做的就是把這50篇文章放到文章放到文章列表前100位至少一天;另外,這個(gè)網(wǎng)站暫時(shí)不提供投反對(duì)票的功能。

為了產(chǎn)生一個(gè)能夠隨著時(shí)間流逝而不斷減少的評(píng)分,程序需要根據(jù)文章的發(fā)布時(shí)間和當(dāng)前時(shí)間來計(jì)算文章的評(píng)分,具體的計(jì)算方法為:將文章得到的支持票數(shù)乘以一個(gè)常量,然后加上文章的發(fā)布時(shí)間,得出的結(jié)果就是文章的評(píng)分。

我們使用從UTC時(shí)區(qū)1970年1月1日到現(xiàn)在為止所經(jīng)過的秒數(shù)來計(jì)算文章的評(píng)分,這個(gè)值通常被成為Unix時(shí)間。之所以選擇使用Unix時(shí)間,是因?yàn)樗心軌蜻\(yùn)行Redis的平臺(tái)上面,使用編程語言獲取這個(gè)值都是非常簡(jiǎn)單的事情。另外,計(jì)算評(píng)分時(shí)與支持?jǐn)?shù)量相乘的常量為432,這個(gè)常量是通過將一天的秒數(shù)(86400)除以文章展示一天所需的支持票數(shù)量(200得出的):文章沒獲得一張支持票,程序就需要將程序的評(píng)分增加432分。

構(gòu)建文章投票網(wǎng)站除了需要計(jì)算文章評(píng)分之外,還需要使用Redis結(jié)構(gòu)存儲(chǔ)網(wǎng)站上的各種信息。對(duì)于網(wǎng)站里的每一篇文章,程序都使用了一個(gè)散列來存儲(chǔ)文章的標(biāo)題、指向文章的網(wǎng)址、發(fā)布文章的用戶、文章的發(fā)布時(shí)間、文章得到的投票數(shù)量等信息。

我們的文章投票網(wǎng)站將使用兩個(gè)有序集合來存儲(chǔ)文章:

第一個(gè)有序集合的成員為:文章ID、文章的發(fā)布時(shí)間,該有序集合可以使網(wǎng)站按照發(fā)布時(shí)間先后展示文章

第二個(gè)有序集合的成員為:文章ID、文章的評(píng)分,該有序集合可以使網(wǎng)站按照評(píng)分高低展示文章。

為了防止用戶對(duì)同一篇文章進(jìn)行多次投票,網(wǎng)站需要為每一篇文章記錄一個(gè)已投票用戶名單。為此,需要?jiǎng)?chuàng)建一個(gè)存儲(chǔ)所有已經(jīng)投票的用戶ID。

為了盡量節(jié)約內(nèi)存,我們規(guī)定當(dāng)一篇文章發(fā)布期滿一周之后,用戶將不能再對(duì)它進(jìn)行投票,文章的評(píng)分將被固定下來,而積累文章已經(jīng)投票用戶名單的集合會(huì)被刪除。

既然我們已經(jīng)知道了網(wǎng)站計(jì)算文章評(píng)分的方法,也知道了網(wǎng)站存儲(chǔ)數(shù)據(jù)所需的數(shù)據(jù)結(jié)構(gòu),那么現(xiàn)在是時(shí)候?qū)嶋H的實(shí)現(xiàn)這個(gè)投票功能了!

當(dāng)用戶嘗試對(duì)一篇文章進(jìn)行投票時(shí),程序需要使用zscore命令來檢查記錄文章發(fā)布時(shí)間的有序集合,判斷文章的發(fā)布時(shí)間是否未超過一周。

如果文章仍然處于可以投票的時(shí)間范圍之內(nèi),那么程序?qū)⑹褂胹add命令,嘗試將用戶添加到記錄文章已經(jīng)投票用戶名單集合里。

如果添加操作執(zhí)行成功的話,那么說明用戶是第一次對(duì)這篇文章進(jìn)行投票,程序?qū)⑹褂脄incrby命令為文章的評(píng)分增加432分(zincrby命令用于對(duì)有序集合成員的分值進(jìn)行自增操作),并使用hincrby命令對(duì)散列記錄的文章投票數(shù)量進(jìn)行更新(hincrby命令用于對(duì)散列存儲(chǔ)的值執(zhí)行自增操作)。

投票功能實(shí)現(xiàn)代碼:
import time

ONE_WEEK_IN_SECONDS=7*86400  #一周秒數(shù)
VOTE_SCORE=432  #點(diǎn)贊一次增加的分值

#投票
def article_vote(conn,user,article):
    cutoff=time.time()-ONE_WEEK_IN_SECONDS
    #提示:本案例使用冒號(hào)作為分隔符
    if conn.zscore("time:",article)
2、發(fā)布并獲取文章

發(fā)布一篇文章首先需要?jiǎng)?chuàng)建一個(gè)新的文章ID,這項(xiàng)工作可以通過對(duì)一個(gè)計(jì)數(shù)器(counter)執(zhí)行incr命令來完成。

接著程序需要使用sadd將文章發(fā)布者的ID添加到記錄文章已投票用戶名單的集合里面,并使用expire命令為這個(gè)集合設(shè)置一個(gè)過期時(shí)間,讓Redis在文章發(fā)布期滿一周之后自動(dòng)刪除這個(gè)集合。

之后,程序會(huì)使用hmset命令來存儲(chǔ)文章的相關(guān)信息,并執(zhí)行兩個(gè)zadd命令,將文章的初始評(píng)分(initial score)和發(fā)布時(shí)間分別添加到兩個(gè)相應(yīng)的有序集合里面。

#發(fā)布文章
def post_article(conn,user,title,link):
    article_id=str(conn.incr("article:"))

    voted="voted:"+article_id

    conn.sadd(voted,user)
    conn.expire(voted,ONE_WEEK_IN_SECONDS)

    now=time.time()
    article="article:"+article_id
    conn.hmset(article,{
        "title":title,#文章標(biāo)題
        "link":link,#文章鏈接
        "poster":user,
        "time":now,
        "votes":1
    })

    conn.zadd("score:",article,now+VOTE_SCORE)
    conn.zadd("time",article,now)

    return article_id

好了,我們已經(jīng)陸續(xù)實(shí)現(xiàn)了文章的投票功能和文章發(fā)布功能,接下來要考慮的就是如何取出評(píng)分最高的文章已經(jīng)如何取出最新發(fā)布的文章。

為了實(shí)現(xiàn)這兩個(gè)功能,

首先需要使用zrevrange命令取出多個(gè)文章ID

然后再對(duì)每個(gè)文章ID執(zhí)行一次hgetall命令來取出文章的詳細(xì)信息。

這個(gè)方法既可以用于取出評(píng)分最高的文章,又可以用于取出最新發(fā)布的文章。

注意:因?yàn)橛行蚣细鶕?jù)成員的分值從小到大排列,所以使用zrevrange命令,以【分值從大到小】的排列順序取出文章ID才是正確的做法。
ARTICLES_PER_PAGE=25 #每頁展示數(shù)量

def get_articls(conn,page,order="score:"):
    start=(page-1)*ARTICLES_PER_PAGE  #設(shè)置文章的起始索引
    end=start+ARTICLES_PER_PAGE-1     #設(shè)置文章的結(jié)束索引

    ids=conn.zrevrange(order,start,end) #獲取多個(gè)文章ID

    articles=[]

    for id in ids:
        article_data=conn.hgetall(id)
        article_data["id"]=id
        articles.append(article_data)
    return articles

雖然我們構(gòu)建的網(wǎng)站現(xiàn)在已經(jīng)可以展示最新發(fā)布的文章和評(píng)分最高的文章了,但它還不具備目前很多投票網(wǎng)站都支持的群組【group】功能:可以讓用戶看見與特定話題有關(guān)的文章,比如:【可愛的動(dòng)物】、【歷史】、【政治】等等。

3、對(duì)文章進(jìn)行分組

群組功能由兩個(gè)部分組成,一個(gè)部分負(fù)責(zé)記錄文章屬于哪個(gè)群組,另一部分負(fù)責(zé)取出群組里面的文章。為了記錄各個(gè)群組都保存了哪些文章,網(wǎng)站需要為每個(gè)群組創(chuàng)建一個(gè)集合,并將所有同屬一個(gè)群組的文章ID都記錄到那個(gè)集合里面。

#將文章添加到群組里面的方法,以及從群組里面移除文章的方法
def add_remove_groups(conn,article_id,to_add=[],to_remove=[]):
    article="article:"+article_id
    for group in to_add:
        conn.sadd("group:"+group,article) #將文章添加到它所屬的群組里面
    for group in to_remove:
        conn.srem("group:"+group,article) #從群組里面移除文章

初看上去,可能會(huì)有讀者覺得使用集合來記錄群組文章并沒有多大用處。到目前為止,我們只看到了集合結(jié)構(gòu)檢查某個(gè)元素是否存在的能力,但實(shí)際上Redis不僅可以對(duì)多個(gè)集合執(zhí)行操作,甚至在一些情況下,還可以在集合和有序集合之間執(zhí)行操作。

為了能夠根據(jù)評(píng)分對(duì)群組文章進(jìn)行排序和分頁,網(wǎng)站需要將同一個(gè)群組里面的所有文章都按照評(píng)分有序的存儲(chǔ)到一個(gè)有序集合里面。Redis的zinterstore命令可以接受多個(gè)集合和多個(gè)有序集合作為輸入,找出所有同時(shí)存在于集合和有序集合的成員,并以幾種不同的方式來合并【combine】這些成員的分值(所有集合成員的分值都會(huì)被視為:1)。對(duì)于我們的文章投票網(wǎng)站來說,程序需要使用zinterstore命令選出相同成員中最大的那個(gè)分值來作為交集成員的分值:取決于所使用的排序選項(xiàng),這些分值既可以是文章的評(píng)分,也可以是文章的發(fā)布時(shí)間。

通過對(duì)存儲(chǔ)群組文章的集合和存儲(chǔ)文章評(píng)分的有序集合執(zhí)行zinterstore命令,程序可以得到按照文章評(píng)分順序的群組文章;

而通過對(duì)存儲(chǔ)群組文章的集合和存儲(chǔ)文章發(fā)布時(shí)間的有序集合執(zhí)行zinterstore命令,程序則可以得到按照文章發(fā)布時(shí)間排序的群組文章。如果群組包含的文章非常多,那么執(zhí)行zinterstore命令就會(huì)比較花時(shí)間,為了盡量減少Redis的工作量,程序會(huì)將這個(gè)命令的計(jì)算結(jié)果緩存60秒。

#分頁并獲取群組文章
def get_group_articles(conn,group,page,order="score:"):
    key=order+group #為每個(gè)群組的每種排列順序都創(chuàng)建一個(gè)鍵
    #檢查是否已有緩存的排序結(jié)果,如果沒有的話現(xiàn)在就進(jìn)行排序
    if not conn.exists(key):
        conn.zinterstore(key,
                         ["group:"+group,order],
                         aggregate="max")
        conn.expire(key,60) #讓redis在60秒后自動(dòng)刪除這個(gè)有序集合
    return get_articls(conn,page,key)
友情提示,上面只是部分代碼,無法直接運(yùn)行,只需要先理解思路就行。

上一篇文章: Python--Redis實(shí)戰(zhàn):第一章:初識(shí)Redis:第二節(jié):Redis數(shù)據(jù)結(jié)構(gòu)簡(jiǎn)介
下一篇文章:Python--Redis實(shí)戰(zhàn):第二章:使用Redis構(gòu)建Web應(yīng)用:第一節(jié):登錄和cookie緩存

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/42570.html

相關(guān)文章

  • Python--Redis實(shí)戰(zhàn)一章初識(shí)Redis:第二節(jié):Redis數(shù)據(jù)結(jié)構(gòu)簡(jiǎn)介

    摘要:上一篇文章實(shí)戰(zhàn)第一章初識(shí)第一節(jié)簡(jiǎn)介下一篇文章實(shí)戰(zhàn)第一章初識(shí)第三節(jié)你好文章投票試煉可以存儲(chǔ)鍵與種不同的數(shù)據(jù)結(jié)構(gòu)類型之間的映射,這中數(shù)據(jù)結(jié)構(gòu)類別分別是字符串列表集合散列和有序集合。 上一篇文章:Python--Redis實(shí)戰(zhàn):第一章:初識(shí)Redis:第一節(jié):Redis簡(jiǎn)介下一篇文章:Python--Redis實(shí)戰(zhàn):第一章:初識(shí)Redis:第三節(jié):你好Redis-文章投票試煉 Redis可...

    ghnor 評(píng)論0 收藏0
  • Python--Redis實(shí)戰(zhàn):第二章:使用Redis構(gòu)建Web應(yīng)用:第一節(jié):登錄和cookie緩存

    摘要:需要在服務(wù)中存儲(chǔ)更多信息,如果使用的是關(guān)系數(shù)據(jù)庫,那么載入和存儲(chǔ)的的代價(jià)可能會(huì)很高。這次我們使用令牌來引用關(guān)系數(shù)據(jù)庫表中負(fù)責(zé)存儲(chǔ)用戶登錄信息的條目。而我們要做的就是適用重新實(shí)現(xiàn)登錄功能,取代由關(guān)系數(shù)據(jù)庫實(shí)現(xiàn)的登錄功能。 上一篇文章:Python--Redis實(shí)戰(zhàn):第一章:初識(shí)Redis:第三節(jié):你好Redis-文章投票試煉下一篇文章:Python--Redis實(shí)戰(zhàn):第二章:使用Redi...

    makeFoxPlay 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<