使用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)]