文档章节

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)

© 著作权归作者所有

共有 人打赏支持
lan_cyl
粉丝 0
博文 9
码字总数 8771
作品 0
武汉
Java的位运算符——与(&)、非(~)、或(|)、异或(^)

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

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

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

cugwyman
2017/02/04
0
0
《C Primer Plus》读书笔记——数组和指针(1)

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

cugwyman
2017/02/06
0
0
Docker学习笔记——构建镜像

Docker有两种构建镜像的方式: 使用docker commit命令; 使用Dockerfile文件; 以下分别介绍这两种方式。 1.docker commit 使用命令创建镜像的步骤如下: 1. 运行容器; 2. 对容器进行修改;...

dendi_hust
2017/12/13
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

没有更多内容

加载失败,请刷新页面

加载更多

Spring Boot 使用parent方式引用时 获取值属性方式默认@

采用官网提供的 引入依赖时,application.properties中的值变量,无法通过${}获取,这是由于Spring Boot 已经将字符方式调整为 <resource.delimiter>@</resource.delimiter>。故如果在,工程中...

翱翔fly
16分钟前
1
0
HTTPS证书验证流程及SSL证书生成步骤【附nginx开启https配置】

------------------------------------------------------------ HTTPS证书验证流程(极简化版) 1.客户端向服务端请求证书(server.crt) 2.服务端下发证书(server.crt) 3.客户端用预制的...

xiaomin0322
17分钟前
1
0
预编译sql语句和参数化sql能有效防止——sql注入攻击——

预编译和参数化处理sql原理类似: 参数化处理sql 是将参数进行了字符串化处理,把参数中的单引号,井号#,等都做了转义处理,进而在执行sql语句时不会被当做sql中的定界符和指定符来执行。 ...

fang_faye
18分钟前
1
0
springboot最全配置解释

​​​​​​​# ----------------------------------------# 核心属性# ----------------------------------------# 文件编码banner.charset= UTF-8# 文件位置banner.locati...

废柴大叔
19分钟前
72
1
(大致了解下)从单机到2000万QPS: 知乎Redis平台发展与演进之路

导读:知乎存储平台团队基于开源Redis 组件打造的知乎 Redis 平台,经过不断的研发迭代,目前已经形成了一整套完整自动化运维服务体系,提供很多强大的功能。本文作者是是该系统的负责人,文...

Ocean_K
26分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部