使用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/

转载于:https://www.cnblogs.com/gattaca/p/6958789.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值