文档章节

Redis学习——举个栗子

lan_cyl
 lan_cyl
发布于 2017/04/06 16:45
字数 679
阅读 3
收藏 0

原文地址:1.3 文章投票系统

1. 需求分析

要做一个可以对文章进行投票的系统,文章的排名跟得票数和发布时间相关,得票越多发布时间越近,排名越高。

一个简单的评分函数:score = post_time_in_seconds + votes * (1 * 24 * 60 *60) / 200

其中post_time_in_seconds是文章发布时间,取Unix time,即从1970年1月1日至发布时经过的秒数
votes为文章得票数,最后一项为每一票的权重。可以看出200票的权重等于一天的时间

效果类似于http://stackoverflow.com/

2. 存储结构设计

2.1 文章存储:

数据结构:hash
key: article:article_id
value:title: title, link: article_url, poster: user:user_id, time: post_time_in_seconds, votes:200

跟普通的关系数据库存储结构差不多

看个例子,图片源于原文: 以HASH结构存储文章的例子

2.2 时间排名的存储:

数据结构:zset
key: time:
value:'article:article_id': post_time_in_seconds

2.3 得分排名的存储:

数据结构:zset key: score:
value: 'article:article_id': score

类似对time和score两个字段分别做了索引

看个例子,图片源于原文: 以ZSET结构存储文章的排名

2.4 投票者的存储

数据结构:set
key: voted:article_id
value:user:user_id

记录一篇文章的所有投票者,用MySQL要更麻烦一些

看个例子,图片源于原文: 以ZSET结构存储文章的排名

2.5 分组信息的存储

数据结构:set
key: groups:group_name
value:article:article_id

看个例子,图片源于原文,score:programming是两个集合交叉的结果: 以ZSET结构存储文章的排名

3. 功能实现

ONE_WEEK_IN_SECONDS = 7 * 86400
VOTE_SCORE = 86400 / 200

# 给文章投票,当前仅支持投赞成票
def article_vote(conn, user, article):
    # vote time is one week
    cutoff = time.time() - ONE_WEEK_IN_SECONDS
    if conn.zscore('time:', article) < cutoff:
        return
    # if the user hasn't voted for this article before,
    # add the user to the voted:
    # increase this article's score
    # increase this article's votes count
    article_id = article.partition(':')[-1]
    if conn.sadd('voted:' + article_id, user):
        conn.zincrby('score:', article, VOTE_SCORE)
        conn.hincrby(article, 'votes', 1)

# 发表文章
def post_article(conn, user, title, link):
    # increase the article id
    article_id = str(conn.incr('article:'))
    voted = 'voted:' + article_id
    # the poster as the first voted:
    conn.sadd(voted, user)
    conn.expire(voted, ONE_WEEK_IN_SECONDS)

    now = time.time()
    article = 'article:' + article_id

    # add this article
    conn.hmset(article, {
        'title': title,
        'link': link,
        'poster': user,
        'time': now,
        'votes': 1,
    })

    # add this article to the sorted set
    conn.zadd('score:', article, now + VOTE_SCORE)
    conn.zadd('time:', article, now)
    return article_id

# 获取文章
ARTICLE_PER_PAGE = 25
def get_articles(conn, page, order='score:'):
    start = (page-1)*ARTICLE_PER_PAGE
    end = start + ARTICLE_PER_PAGE - 1

    # fetch the article ids
    ids = conn.zrevrange(order, start, end)
    # get article info from ids
    articles = []
    for id in ids:
        article_data = conn.hgetall(id)
        article_data['id'] = id
        article.append(article_data)
    return articles

# 对文章进行分组
def add_remove_groups(conn, article_id, to_add=[], to_remove=[]):
    article = 'article:' + article_id
    # add this article to the group
    for group in to_add:
        conn.sadd('group:' + group, article)
    # remove this article fromt the group
    for group in to_remove:
        conn.srem('group:' + group, article)

# 获取一组文章
def get_group_articles(conn, group, page, order='score:'):
    key = order + group
    # add this group's sort info
    if not conn.exists(key):
        conn.zinterstore(key,
            ['group:'+group, order],
            aggregate='max',
        )
        conn.expire(key, 60)
    # get a page of articles from the key
    return get_articles(conn, page, key)

© 著作权归作者所有

共有 人打赏支持
下一篇: Redis学习
lan_cyl
粉丝 1
博文 12
码字总数 15685
作品 0
武汉
私信 提问
Java的位运算符——与(&)、非(~)、或(|)、异或(^)

1.与运算符(&),其使用规律如下: 两个操作数中位都为1,结果才为1,否则结果为0,举个栗子: a=5,b=3 a 和b 与的结果是:1 5 0101 3 & 0011 0001 => 1 2.或运算符(|),其运算规律如下...

varuscn
2018/02/27
0
0
《C Primer Plus》读书笔记——递归

递归的原理 一个函数调用其本身,此调用过程为递归(recursion)。 递归的使用 举个栗子: 输出如下: 递归的基本原理 每级递归都使用其私有变量(如例子中的n) 每次函数调用都返回前一级(...

cugwyman
2017/02/04
0
0
【9.16源创会郑州站】干了这碗胡辣汤 开源内裤带回家

郑州源创会圆满落幕,PPT下载查看文末链接,本次活动详情点击这里。 源创会首次到达中原地区,探索这片孕育中华文明的神奇土地。我们秉着“自由,开放,分享”的思想,为郑州当地开发者提供一...

新垣吉衣OSC
2018/09/18
605
11
《C Primer Plus》读书笔记——数组和指针(1)

背景 此章笔记以读者有简单的C语言基础,对数组(array)、指针(pointer)有初步了解及应用,想扎实基础或深入探究为背景而写。 数组的使用 举个栗子: 输出如下: 用标识符常量表示数组大小...

cugwyman
2017/02/06
0
0
《How Tomcat Works》读书笔记(一)A Simple Web Server

一个基于JAVA的Web服务器主要使用两个重要类:java.net.Socket和java.net.ServerSocket。 因为web服务器使用HTTP与客户端进行通信,所以也称HTTP服务器。 1.1 HTTP HTTP请求:  Method—U...

奋斗的海贼
2013/01/14
0
16

没有更多内容

加载失败,请刷新页面

加载更多

如何在 Linux 系统查询机器最近重启时间

在你的 Linux 或类 UNIX 系统中,你是如何查询系统上次重新启动的日期和时间?怎样显示系统关机的日期和时间? last 命令不仅可以按照时间从近到远的顺序列出该会话的特定用户、终端和主机名...

来来来来来
35分钟前
0
0
Redis协议是什么样的

前言 我们用过很多redis的客户端,有没有相过自己撸一个redis客户端? 其实很简单,基于socket,监听6379端口,解析数据就可以了。 redis协议 解析数据的过程主要依赖于redis的协议了。 我们...

春哥大魔王的博客
52分钟前
2
0
乱入Linux界的我是如何学习的

欢迎来到建哥学Linux,咳!咳!咳!开个玩笑哈,我是一个IT男,IT界的入门选手,正在学习Linux。 在之前,一直想进军IT界,学习IT技术,但是苦于没有人指导,也不知道学什么,最开始我自己在...

linuxCool
今天
1
0
携程Apollo统一配置中心的搭建和使用(java)

一.Apollo配置中心介绍 1、What is Apollo 1.1 Apollo简介 Apollo(阿波罗)是携程框架部门研发的开源配置管理中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到...

morpheusWB
今天
1
0
远程获得的有趣的linux命令

使用这些工具从远程了解天气、阅读资料等。 我们即将结束为期 24 天的 Linux 命令行玩具日历。希望你有一直在看,如果没有,请回到开始,从头看过来。你会发现 Linux 终端有很多游戏、消遣和...

Linux就该这么学
今天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部