• 使用Redis构建文章投票网站


    涉及到的key:

    1. article_time, 记录文章的发布时间,zset结构

    2. article_score, 记录文章的得分, zset结构

      得分 = 发布时间 + 投票用户数 X 432

    3. voted_article_id, 记录文章的投票用户集合,文章的发布者默认为文章的投票用户,set结构

    4. article_article_id, 用来描述文章,hash结构

    5. group_groupname, 群组groupname下的文章集合,set结构

    6. score_groupname, 群组groupname下的文章得分集合,zset结构

    # python3
    # -*- coding: utf-8 -*-
    
    import redis
    import time
    
    ONE_WEEK_IN_SECONDS = 7 * 86400
    # 如果一篇文章获得200个赞,那么这篇文章就是有趣的
    VOTE_SCORE = 86400 / 200
    ARTICLES_PER_PAGE = 25
    
    def redis_init(redis):
        # article_time记录文章发布时间
        redis.zadd('article_time', article_100408=1496762197, article_100635=1496769721, article_100716=1496760089)
        # article_score记录文章得分
        redis.zadd('article_score', article_100408=1496766517, article_100635=1496770153, article_100716=1496765705)
        # voted_article_id记录编号为article_id的文章的点赞用户集合
        redis.sadd('voted_100408', 'user_234487', 'user_253378', 'user_364680',
                   'user_132097', 'user_350917')
        # 用hash描述每篇文章
        article_desc = {'title':'kunlun', 'link':'www.kunlun.com', 'poster':'user_234487',
                        'time':1441728000, 'votes':523}
        redis.hmset('article_100408', article_desc)
        article_desc = {'title': 'zhuxian', 'link': 'www.zhuxian.com', 'poster': 'user_234488',
                        'time': 1081440000, 'votes': 677}
        redis.hmset('article_100635', article_desc)
        article_desc = {'title': 'soushenji', 'link': 'www.soushenji.com', 'poster': 'user_234489',
                        'time': 1187280000, 'votes': 421}
        redis.hmset('article_100635', article_desc)
        # 记录文章总数
        redis.set('article_index', 200000)
    
    # 用户给文章投票
    def article_vote(conn, user, article):
        cutoff = time.time() - ONE_WEEK_IN_SECONDS
        if conn.zscore('article_time', article) < cutoff:
            return
    
        article_id = article.partition('_')[-1]
        if conn.sadd('voted_' + article_id, user):
            conn.zincrby('article_score', article, VOTE_SCORE)
            conn.hincrby(article, 'votes', 1)
    
    # 发布新文章
    def post_article(conn, user, title, link):
        article_id = str(conn.incr('article_index'))
    
        voted = 'voted_' + article_id
        # poster默认为文章的投票用户
        conn.sadd(voted, user)
        # 设置key过期时间
        conn.expire(voted, ONE_WEEK_IN_SECONDS)
    
        now = time.time()
        article = 'article_' + article_id
        conn.hmset(article, {
            'title': title,
            'link': link,
            'poster': user,
            'time': now,
            'votes': 1,
        })
    
        conn.zadd('article_score', article, now + VOTE_SCORE)
        conn.zadd('article_time', article, now)
    
        return article_id
    
    # 取出评分最高的文章
    # 取最新发布的文章,order='article_time'
    # page, 按页取
    def get_articles(conn, page, order='article_score'):
        start = (page-1) * ARTICLES_PER_PAGE
        end = start + ARTICLES_PER_PAGE - 1
    
        ids = conn.zrevrange(order, start, end)
        articles = []
        for id in ids:
            article_data = conn.hgetall(id)
            article_data['id'] = id
            articles.append(article_data)
    
        return articles
    
    # 添加文章到群组,或者从群组里删除文章
    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)
    
    # 获取群组中的文章
    def get_group_articles(conn, group, page, order='article_score'):
        key = order + group
        if not conn.exists(key):
            conn.zinterstore(key,
                             ['group_' + group, order],
                             aggregate='max'
                             )
            # 缓存60s
            conn.expire(key, 60)
        return get_articles(conn, page, key)
    
    r = redis.Redis(host='redis_serverip', port=6379, password='redis_passwd', db=0)
    
    # redis_init(r)
    
    # article_vote(r,'use_115423', 'article_100408')
    #
    # new_article_id =  post_article(r, 'user_5424', 'yingxiongzhi', 'www.yingxiongzhi.com')
    # print('new_article_id:', new_article_id)
    #
    # add_remove_groups(r, 'article_100408')
    #
    # get_group_articles(r, 'programming', 1)

    PS:

        redis-py模块中有两个类:Redis和StrictRedis,两者部分API稍有不同,本文使用Redis这个类。


    反对票的实现:

    def article_against(conn, user, article):
        cutoff = time.time() - ONE_WEEK_IN_SECONDS
        if conn.zscore('article_time', article) < cutoff:
            return
    
        article_id = article.partition('_')[-1]
        if conn.sadd('against_' + article_id, user):
            conn.incrby('article_score', article, -VOTE_SCORE)
            conn.hincrby(article, 'votes', -1)

    移除投票的竞争条件:

    def article_against(conn, user, article):
        cutoff = time.time() - ONE_WEEK_IN_SECONDS
        if conn.zscore('article_time', article) < cutoff:
            return
    
        article_id = article.partition('_')[-1]
        if conn.sadd('against_' + article_id, user):
            pipeline = conn.pipeline()
            
            conn.incrby('article_score', article, -VOTE_SCORE)
            conn.hincrby(article, 'votes', -1)
    
            pipeline.execute()

    参考资料:

    《Redis实战》

    https://pypi.python.org/pypi/redis

    https://redis-py.readthedocs.io/en/latest/

  • 相关阅读:
    JAVA 遍历UFT-8所有中文
    用友U8 | 【固定资产】固定资产常见问题
    用友U8 | 【出纳管理】当前凭证不是出纳管理凭证,不能修改
    用友U8 | 【出纳管理】选中的日记账包含了已制单但没有回写凭证号的日记账,无法制单!
    用友U8 | 【生产订单】工作日历未设定或超出工作日历范围
    用友U8 | 【出纳管理】当前选择的日记账已经制单,上次制单包含其他账户的日记账,请在日记账查询中修改
    用友U8 | 【U8年结】开账结转如何操作?
    用友U8 | 【出纳管理】收支操作生单提示:集合中的143272已经加锁了,不能对集合中的数据进行加锁
    用友U8 | 【出纳管理】银行记账提示:未设置对象变量或with block 变量(91)
    MySQL经典45题(二)
  • 原文地址:https://www.cnblogs.com/gattaca/p/6958789.html
Copyright © 2020-2023  润新知