Reddit的Upvote功能简单实现

在Reddit和Stackoverflow或者知乎上都可以看见有一个Upvote功能,这种功能让用户去维护信息流动。它可以用Redis数据库实现。

##构造数据库 我们用一个zset(由权重+值两部分组成)来存储每篇文章的post时间,zset是排序好的set,它是根据值对应的权重来排序的。这样就可以让文章以时间排序的方式排列显示。

127.0.0.1:6379> zadd time: 1430104804 article:100409
(integer) 1
127.0.0.1:6379> zadd time: 1332075503.49 article:100635
(integer) 1
127.0.0.1:6379> zadd time: 1332082035.26 article:100716
(integer) 1

用另外一个zset来存储每篇文章的排名加权权重,这样就可以让文章以排名权重的方式排列显示。

127.0.0.1:6379> zadd score: 1332225027.26 article:100716
(integer) 1
127.0.0.1:6379> zadd score: 1332075503.49 article:100635
(integer) 1
127.0.0.1:6379> zadd score: 1332065417.47 article:100408
(integer) 1

用一个元素不重复的set来存储对某篇文章投票过用户的id。假设已有三个用户对article:100408投过票。

127.0.0.1:6379> sadd voted:100408 user:234487
(integer) 1
127.0.0.1:6379> sadd voted:100408 user:253378
(integer) 1
127.0.0.1:6379> sadd voted:100408 user:364680
(integer) 1

##实现

#! -*- /bin/user env python
# -*- coding: utf-8 -*-
import redis
import time

ONE_WEEK_IN_SECONDS = 7 * 86400
VOTE_SCORE = 432 # 自定义投票后增加的排序权重
conn = redis.StrictRedis(host='localhost', port=6379, db=0)

def article_vote(conn, user, article):
    cutoff = time.time() - ONE_WEEK_IN_SECONDS
    # 只能只对最近一个星期内的文章进行投票
    if conn.zscore('time:', article) < cutoff:
        return

    article_id = article.partition(':')[-1]
    # 在voted:article_id set中添加对这篇文章 upvote的用户,防止重复upvote
    if conn.sadd('voted:' + article_id, user):
        # 对这篇文章增加排序权重
        conn.zincrby('score:', article, VOTE_SCORE)
        # 维持一个hashtable对文章的upvote计数
        conn.hincrby(article, 'votes', 1)

def post_article(conn, user, title, link):
    # 从1开始自动编号生成文章id
    article_id = str(conn.incr('article:'))

    voted = 'voted:' + article_id
    conn.sadd(voted, user)
    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('score:', now + VOTE_SCORE, article)
    conn.zadd('time:', now, article)

    return article_id

if __name__ == '__main__':
    # 增加文章
    article_id = post_article(conn, 'user:1000', 'the implementation of Upvote', 'http://tuzhii.com/')
    # 对某篇文章进行Upvote
    article_vote(conn, 'user:2233345886', 'article:20')
    article_vote(conn, 'user:1', 'article:100408')
    article_vote(conn, 'user:2', 'article:100408')
    article_vote(conn, 'user:3', 'article:100408')

##Upvote结果

查看set中voted:100408是哪些用户投票的

SMEMBERS voted:100408

127.0.0.1:6379> SMEMBERS voted:100408
1) "user:1"
2) "user:5"
3) "user:4"
4) "user:234487"
5) "user:2"
6) "user:3"
7) "user:253378"
8) "user:364680"

查看哈希表article:100408中项votes的计数,即投票数,可以得到投票数为8。

HGET article:100408 votes

##Reference [1].Redis in Action. Page16~18

[2].http://redis.io/commands/zscore

转载于:https://my.oschina.net/lvyi/blog/406874

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值