来自《Redis 实战》第一章

对于 Redis 数据结构类型及使用不太清楚的可以参考 此链接

需求:

  1. 网站需要根据文章的发布时间和文章获得的投票数量计算出一个评分,然后按照这个评分来决定如何排序和展示文章。
  2. 得分的计算方式为:将文章得到的支持票数乘以一个常量(假设为432),然后加上文章的发布时间(定为从1970年1月1日到现在经过的秒数),得出的结果就是文章的评分。
  3. 同时需要提供既能按照发布时间来展示文章,又能根据评分来展示文章的功能。
  4. 如果文章发布超过一周,则不提供投票功能。

Redis 中结构设计:

文章信息
value 结构 HASH
key article:<文章id>   例:article:100408 (使用冒号来区分名字的不同部分,100408为文章ID)
value 保存的键值对包含 标题、链接、发布者、发布时间、得票数 信息
文章发布时间信息
value 结构 ZSET
key time:
value

成员为 article:<文章id>   分值为 1997年1月1日到现在的秒数

例:article:100408 (成员) - 1332065474.47 (分值)

文章评分信息
value 结构 ZSET
key score:
value

成员为 article:<文章id>   分值为 文章评分

例:article:100408 (成员) - 13320656524.47 (分值)

投票记录信息
value 结构 SET
key voted:<文章id> 例:voted:100408
value user:<用户id> 例:user:234487

Python 实现的代码

import time

ONE_WEEK_IN_SECONDS = 7 * 24 * 60 * 60
VOTE_SCORE = 432
ARTICLES_PER_PAGE = 25 '''
用户对文章进行投票(目前没有考虑事务问题)
用户尝试投票时,使用 ZSCORE 命令检查记录文章发布时间的有序集合,判断文章的发布时间是否未超过一周,
如果仍可投票,使用 SADD 命令,尝试将用户添加到 记录文章已投票用户名单的集合里面,
如果成功,说明此用户是第一次为这个文章投票,此时使用 ZINCRBY 命令为文章添加 432 的评分数,
并使用 HINCRBY 命令对散列记录的文章投票数量进行更新
'''
def article_vote(conn, user, article):
# 计算投票的截止时间
cutoff = time.time() - ONE_WEEK_IN_SECONDS
if conn.zscore('time:', article) < cutoff:
# 超过投票截止时间则直接返回
return
# 获取文章 ID 部分
article_id = article.partition(':')[-1]
# 尝试将投票用户添加到文章已投票用户集合中
if conn.sadd('voted:' + article_id, user):
# 为文章添加评分
conn.zincrby('score:', article, VOTE_SCORE)
# 更新文章的得票数(+1)
conn.hincrby(article, 'votes', 1) '''
发布文章
通过对一个计数器执行 INCR 命令来生成文章id,
接着使用 SADD 将文章发布者的id 添加到记录文章已投票用户名单的
集合里面(这个集合需要使用 EXPIRE 命令设置为一周的过期时间,因为只有一周内的文章可以投票),
之后使用 HMSET 命令来存储文章的相关信息,并执行两个 ZADD 命令,
将文章的初始评分和发布时间分别添加到两个相应的有序集合里面
'''
def post_article(conn, user, title, link):
# 通过自增方式生成文章 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:', article, now + VOTE_SCORE)
conn.zadd('time:', article, now)
return article_id '''
获取指定排序后的文章信息
使用 ZREVRANGE 取出多个文章id, 再对每个文章id 执行一次 HGETALL 来取出文章的详细信息
'''
def get_articles(conn, page, order='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

Redis 练习(一)的更多相关文章

  1. 使用redis构建可靠分布式锁

    关于分布式锁的概念,具体实现方式,直接参阅下面两个帖子,这里就不多介绍了. 分布式锁的多种实现方式 分布式锁总结 对于分布式锁的几种实现方式的优劣,这里再列举下 1. 数据库实现方式 优点:易理解 缺 ...

  2. Ignite性能测试以及对redis的对比

    测试方法 为了对Ignite做一个基本了解,做了一个性能测试,测试方法也比较简单主要是针对client模式,因为这种方法和使用redis的方式特别像.测试方法很简单主要是下面几点: 不作参数优化,默认 ...

  3. mac osx 安装redis扩展

    1 php -v查看php版本 2 brew search php|grep redis 搜索对应的redis   ps:如果没有brew 就根据http://brew.sh安装 3 brew ins ...

  4. Redis/HBase/Tair比较

    KV系统对比表 对比维度 Redis Redis Cluster Medis Hbase Tair 访问模式    支持Value大小 理论上不超过1GB(建议不超过1MB) 理论上可配置(默认配置1 ...

  5. Redis数据库

    Redis是k-v型数据库的典范,设计思想及数据结构实现都值得学习. 1.数据类型 value支持五种数据类型:1.字符串(strings)2.字符串列表(lists)3.字符串集合(sets)4.有 ...

  6. redis 学习笔记(2)

    redis-cluster 简介 redis-cluster是一个分布式.容错的redis实现,redis-cluster通过将各个单独的redis实例通过特定的协议连接到一起实现了分布式.集群化的目 ...

  7. redis 学习笔记(1)

    redis持久化 snapshot数据快照(rdb) 这是一种定时将redis内存中的数据写入磁盘文件的一种方案,这样保留这一时刻redis中的数据镜像,用于意外回滚.redis的snapshot的格 ...

  8. python+uwsgi导致redis无法长链接引起性能下降问题记录

    今天在部署python代码到预生产环境时,web站老是出现redis链接未初始化,无法连接到服务的提示,比对了一下开发环境与测试环境代码,完全一致,然后就是查看各种日志,排查了半天也没有查明是什么原因 ...

  9. nginx+iis+redis+Task.MainForm构建分布式架构 之 (redis存储分布式共享的session及共享session运作流程)

    本次要分享的是利用windows+nginx+iis+redis+Task.MainForm组建分布式架构,上一篇分享文章制作是在windows上使用的nginx,一般正式发布的时候是在linux来配 ...

  10. windows+nginx+iis+redis+Task.MainForm构建分布式架构 之 (nginx+iis构建服务集群)

    本次要分享的是利用windows+nginx+iis+redis+Task.MainForm组建分布式架构,由标题就能看出此内容不是一篇分享文章能说完的,所以我打算分几篇分享文章来讲解,一步一步实现分 ...

随机推荐

  1. java.lang.reflect.UndeclaredThrowableException: null Caused by: org.apache.zookeeper.KeeperException$UnimplementedException: KeeperErrorCode = Unimplemented for

    java.lang.reflect.UndeclaredThrowableException: null    at org.springframework.util.ReflectionUtils. ...

  2. Linux定制化RPM包

    定制化RPM包 1.Linux安装软件方法 1- rpm/yum安装 简单.速度快,但是不能定制安装 RPM RedHat Package Manager(RPM软件包管理器) 2- 二进制安装 解压 ...

  3. 13.浏览器屏幕缩放bug修复

    目录 问题:浏览器缩放时,轮播图显示不全,滚动水平滚动条,发现图片缺失 解决:隐藏水平滚动条,页面都只提供垂直滚动条的需求 问题:浏览器缩放时,轮播图显示不全,滚动水平滚动条,发现图片缺失 解决:隐藏 ...

  4. sql 语句系列(null 值处理)[八百章之第二章]

    查找只存在一个表中的数据 有两张表: EMP: select * from emp DEPT: 他们有共同的属性:deptno 现在要查询EMP 中的deptno不等于DEPTNO的deptno项. ...

  5. 面向对象第四单元(UML)及期末总结

    前言 统一建模语言(英语:Unified Modeling Language,缩写 UML),是软件架构设计建模和规约的语言. 在UML系统开发中有三个主要的模型: 功能模型:从用户的角度展示系统的功 ...

  6. Natas27 Writeup(mysql溢出截断漏洞)

    Natas27: 一个登录节界面,查看源码. <html> <head> <!-- This stuff in the header has nothing to do ...

  7. Postgresql实战经验之alter table 开小差了

    Postgresql实战经验之alter table 开小差了 今天需要将一张有数据的表中一个字段varchar 类型转换为timestamp类型,但是pg的alter table 语句却开小差,出现 ...

  8. datetime和time

    datetime和time 1.datetime模块 import datetimenow = datetime.datetime.now() #时间对象print(now,type(now))pri ...

  9. django之forms组件,cookie&session

    forms组件 先自己实现注册功能,并且对用户输入的信息加限制条件如果用户输入的信息不符合条件,前端展示报错信息 from django.shortcuts import render,HttpRes ...

  10. 两片74门实现的双边沿D触发器

    最近一个项目需要时钟上升沿和下降沿都可以触发的D触发器,但并没有找到符合要求的商品IC.也去看了一些文献,但都是给的示意图然后用分立元件实现的(应该是准备做成IC).这里给出一种最少2个IC就能搭出来 ...