涉及到的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实战》