• 使用python+redis实现文章发布,投票,分组排名功能


    1.逻辑

      实例来源于<<Redis实战>>这本书。

      构建一个投票网站,为这个网站设置一些数值和限制条件:如果一篇文章获得至少200张支持票,那么网站就认为这篇文章是用户喜欢的文章;假如这个网站发布1000篇文章,而其中50篇符合网站对有趣文章的要求,那么网站要把这50篇网站放到首页推荐前100位至少一天。为了产生一个能够随时间流逝而不断减少的评分,程序需要根据文章的发布时间和当前的时间来计算文章的评分,具体计算方法:将文章得到的支持票数乘以一个常量,然后加上文章的发布时间,得出的结果就是文章的评分。

      文章发布时间使用Unix时间戳表示,计算评分时, 与支持票数量相乘的变量为432,这个常量是通过将一天的秒数(86400)除以文章展示一天所需的票数(200)得出的,文章没获得一张支持票,程序就需将文章的评分增加432分。

      

    2.实现代码

     #-*- coding: UTF-8 -*- 
    import redis
    import time
    
    ONE_WEEK_IN_SECONDS = 604800
    VOTE_SCORE          = 240.00
    
    pool  = redis.ConnectionPool(host = "127.0.0.1", port = 6379, password = '')
    redis = redis.Redis(connection_pool = pool)
    
    #发布文章
    def post(articleData, redis = redis):
            articleId = str(redis.incr('article:'))
    
            '#保存文章'
            article = 'article:' + articleId
            redis.hmset(article,  mapping = articleData)
    
            '#将文章与发布时间通过一个有序集合进行关联'
            redis.zadd('time',article, articleData['time'])
    
            '#为自己投初始票'
            vote(article, articleData['poster']) 
    
            '修改文章评分'
            score(article, redis)
            
            return article
    
    #为文章投票
    def vote(article, user, redis = redis):
            global ONE_WEEK_IN_SECONDS
            '#投票,和用户绑定'
            voted       = 'voted:' + article.partition(':')[-1]
            articleData = redis.hgetall(article)
            postTime    = redis.zscore('time', article);
    
            #一周之前的文章不能投票
            tempTime = time.time() - ONE_WEEK_IN_SECONDS;
            if postTime and postTime <= tempTime:
                    return False
    
            #一个用户只能投一票,判断用户是否已经投过
    
            if (redis.sismember(voted, user)):
                    return False
            
            redis.sadd(voted, articleData[b'poster'])
            redis.expire(voted, ONE_WEEK_IN_SECONDS)
    
    #更新章的评分      
    def score(article, redis = redis):
            global VOTE_SCORE
            
            '#将文章与评分通过一个有序集合进行关联'
            redis.zincrby('score', article, VOTE_SCORE)
            redis.hincrby(article, 'votes', 1)
    
    #按特定的方式(发布时间,评分)降序取出文章
    def get_articles(order, page = 1, limit = 25, redis = redis):
            start       = (page - 1) * limit
            end         = start + limit - 1
            articleIds  = redis.zrange(order, start, end, desc = True)
            articleList = {};
    
            for id in articleIds:
                    articleData       = redis.hgetall(id)
                    articleData['id'] = id
                    articleList[id]   = articleData
      
            return articleList
    
    #设置,移除文章分组
    def add_remove_group(article, add = [], remove = [], redis = redis):
            for group in add:
                    groupKey = 'group:' + group
                    redis.sadd(groupKey, article)
            for group in remove:
                    redis.srem(groupKey, article)
    
    #按评分或时间排名取出分组下的文章
    def get_group_articles(group, order, page = 25, limit = 25, redis = redis):
            key = order + group
    
            if (not redis.exists(key)):
                    redis.zinterstore(key,
                    ['group:' + group, order],
                    aggregate = 'max'
                    )
                    redis.expire(key, 5)
    
            return get_articles(key, page, limit)
    

      

    3.发布文章

      调用

    article   = post(articleData)
    articleId = article.partition(':')[-1]
    
    add_remove_group(article, add = ['redis'])
    
    #获取文章
    print('----------------------------------Article ID------------------------------')
    print(articleId)
    
    #获取文章
    print('----------------------------------Article------------------------------')
    print(redis.hgetall(article))
    
    #获取文章发布时间
    print('----------------------------------Voted Users------------------------------')
    print(redis.smembers('voted:' + articleId))
    
    #获取所有文章评分,并且按照分数排名
    print('----------------------------------Rank------------------------------')
    print(redis.zrange('score', 0, -1, desc=True, withscores=True))
    
    #获取所有文章发布时间
    print('----------------------------------Post Time------------------------------')
    print(redis.zrange('time', 0, -1, desc=True, withscores=True))
    

      

      输出结果

    88
    ----------------------------------Article------------------------------
    {b'poster': b'user:001', b'title': b'Ptython', b'content': b'hello world', b'votes': b'1', b'time': b'1596951581.718217'}
    ----------------------------------Voted Users------------------------------
    {b'user:001'}
    ----------------------------------Rank------------------------------
    [(b'article:87', 1596951443.171613), (b'article:86', 1596951389.8698218), (b'article:85', 1596951275.8035266), (b'article:84', 1596951174.1960804), (b'article:83', 1596951071.6917884), (b'article:10', 1596816080.909939), (b'article:9', 1596816058.8451862), (b'article:8', 1596816047.3071418), (b'article:7', 1596816011.8706625), (b'article:6', 1596815930.085024), (b'article:5', 1596815917.6721313), (b'article:4', 1596815862.928912), (b'article:3', 1596815838.7520182), (b'article:2', 1596814204.1336813), (b'article:1', 1596813938.6256502), (b'article:88', 240.0)]
    ----------------------------------Post Time------------------------------
    [(b'article:88', 1596951581.718217), (b'article:87', 1596951203.171613), (b'article:86', 1596951149.8698218), (b'article:85', 1596951035.8035266), (b'article:84', 1596950934.1960804), (b'article:83', 1596950831.6917884), (b'article:82', 1596950758.6923993), (b'article:81', 1596950643.6892672), (b'article:80', 1596950633.143089), (b'article:10', 1596815840.909939), (b'article:9', 1596815818.8451862), (b'article:8', 1596815807.3071418), (b'article:7', 1596815771.8706625), (b'article:6', 1596815690.085024), (b'article:5', 1596815677.6721313), (b'article:4', 1596815622.928912), (b'article:3', 1596815598.7520182), (b'article:2', 1596813964.1336813), (b'article:1', 1596813698.6256502)]
    

      

  • 相关阅读:
    什么是字典序算法?
    安装使用zookeeper
    用最快速度将0*10范围内的数进行排序
    自定义schema 流程
    dubbo原理
    jvm 线上命令
    如何实现抢红包算法?
    GC Root 对象有哪些
    Jquery动态绑定事件处理函数 bind / on / delegate
    找出数组中的最小值(es5/es6)
  • 原文地址:https://www.cnblogs.com/xiangdongsheng/p/13455921.html
Copyright © 2020-2023  润新知