使用Redis构建简易社交网站(3)-状态与信息流
目的
本文目的:实现获取主页时间线和状态推送功能。(完整代码附在文章末尾)
相关知识
在我上一篇文章 《使用Redis构建简易社交网站(2)-处理用户关系》中提到了实现用户关注和取消关注功能。
那这篇文章将教会你掌握:1
.redis
基本命令,2
.python
基本命令。
redis基本命令
zadd:将成员加入到有序集合中,并确保其在正确的位置上。
conn = redis.Redis()
conn.zadd("testzset", "member2", 3)
conn.zadd("testzset", "member1", 2)
conn.zadd("testzset", "member3", 1)
执行后:
member3
member1
member2
执行结果:1
,1
,1
zrange:返回有序集合中指定区间内的成员。
conn = redis.Redis()
conn.zrange("testzset", 0, 1)
执行结果:['member3', 'member1']
zrevrange:按分值递减的顺序返回有序集合中指定区间内的成员。
conn = redis.Redis()
conn.zrevrange("testzset", 0, -1)
执行结果:['member2', 'member1', 'member3']
hgetall:返回哈希表中所有的域-值对。
conn = redis.Redis()
conn.hgetall("testhash")
执行结果:{'field1': '2'}
hget:从哈希中获取指定域的值。
conn = redis.Redis()
conn.hget("testhash", "field1")
执行结果:2
pipeline:将多条命令按照先后顺序放进一个队列中,一般配合execute一同使用,原子性(atomic)地执行队列里的命令。
conn = redis.Redis()
pipe = conn.pipeline(True) # 事务开始
pipe.incr("counter")
pipe.incr("counter")
pipe.incr("counter")
pipe.execute() # 事务执行
执行结果:[1, 2, 3]
,通过下标即可获取对应命令的执行结果。
python基本命令
使用格式化拼接字符串:
"My name is %s, I'm %i years old"%('educoder', 2)
执行结果:"My name is educoder, I'm 2 years old"
将字符串转换为浮点数:
float("1.23")
执行结果:1.23
实战例题
编写 get_home_timeline(uid)
函数,实现获得主页时间线的功能,具体参数与要求如下:
- 方法参数
uid
为要获取主页时间线的用户编号; - 获取动态编号的实现:从存储用户主页时间线的有序集合
home:{uid}
中按照分值递减的顺序取出所有成员; - 获取动态详情的实现:遍历动态编号,使用事务一次性获取每个动态编号对应动态详情哈希键
post:{pid}
的所有域-值对; - 返回主页时间线的实现:返回事务执行的结果。
编写 post(uid, content)
函数,实现发布动态并将动态推送给粉丝的功能,具体参数与要求如下:
- 方法参数
uid
为要发布动态的用户编号,content
为要发布的动态内容; - 发布动态的实现:调用第一关中实现的
create_post
方法,并接收返回的动态编号,若发布失败,则取消发布,返回None
; - 获取发布时间的实现:从新发布的动态编号对应的动态详情哈希键
post:{pid}
中获取posted
域; - 更新个人主页的实现:将新发布的动态编号存储到个人主页有序集合键
profile:{uid}
中,分值为转为浮点数后的发布时间; - 更新粉丝主页时间线的实现:遍历用户的粉丝列表
followers:{uid}
,将新发布的动态编号存储到每个粉丝的主页时间线的有序集合home:{follower_id}
中,分值为转为浮点数后的发布时间; - 返回发布结果的实现:返回新发布的动态编号。
测试说明
测试输入:4
;
预期输出:
用户 4 关注 用户 1
关注结果: True测试 post 方法...
创建动态: 1
创建动态: 2
用户 1 的动态列表: ['2', '1']
用户 4 的主页时间线动态编号: ['2', '1']测试 get_home_timeline 方法...
用户 4 的主页时间线: [{'content': 'NEW post from user 1!!!', 'uid': '1', 'user_name': 'test_user1', 'id': '2'}, {'content': 'This is the first post from user 1', 'uid': '1', 'user_name': 'test_user1', 'id': '1'}]
code.py
#code.py
#-*- coding:utf-8 -*-import re
import time
import redisconn = redis.Redis()# 获得主页时间线
def get_home_timeline(uid, page=1, count=30):# 请在下面完成要求的功能#********* Begin *********#post_ids = conn.zrevrange("home:%s"%(uid), 0, -1)pipe = conn.pipeline(True)for pid in post_ids:pipe.hgetall("post:%s"%(pid))return pipe.execute()#********* End *********## 发布动态并将动态推送给粉丝
def post(uid, content):# 请在下面完成要求的功能#********* Begin *********#pid = create_post(uid, content)if not pid:return Noneposted = conn.hget("post:%s"%(pid), "posted")conn.zadd("profile:%s"%(uid), pid, float(posted))followers = conn.zrange("followers:%s"%(uid), 0, -1)pipe = conn.pipeline(False)for follower in followers:pipe.zadd("home:%s"%(follower), pid, float(posted))pipe.execute()return pid#********* End *********## 关注用户
def follow(uid, other_uid):fkey1 = "following:%s"%(uid)fkey2 = "followers:%s"%(other_uid)if conn.zscore(fkey1, other_uid):return Nonenow = time.time()pipe = conn.pipeline(True)pipe.zadd(fkey1, other_uid, now)pipe.zadd(fkey2, uid, now)following, followers = pipe.execute()posts = conn.zrevrange("profile:%s"%(other_uid), 0, 100, withscores=True)if posts:pipe.zadd("home:%s"%(uid), **dict(posts))pipe.hincrby("user:%s"%(uid), 'following', int(following))pipe.hincrby("user:%s"%(other_uid), 'followers', int(followers))pipe.execute()return True# 取消关注
def unfollow(uid, other_uid):fkey1 = "following:%s"%(uid)fkey2 = "followers:%s"%(other_uid)if not conn.zscore(fkey1, other_uid):return Nonepipe = conn.pipeline(True)pipe.zrem(fkey1, other_uid)pipe.zrem(fkey2, uid)following, followers = pipe.execute()posts = conn.zrevrange("profile:%s"%(other_uid), 0, -1)if posts:pipe.zrem("home:%s"%(uid), *posts)pipe.hincrby("user:%s"%(uid), 'following', -int(following))pipe.hincrby("user:%s"%(other_uid), 'followers', -int(followers))pipe.execute()return True# 创建新用户
def create_user(login_name, real_name):login_name = login_name.lower()if conn.hget("users", login_name):return Noneuid = conn.incr("user:id")pipe = conn.pipeline(True)pipe.hset("users", login_name, uid)pipe.hmset("user:%i"%(uid), {'login_name': login_name,'id': uid,'real_name': real_name,'followers': 0,'following': 0,'posts': 0,'last_signup': time.time(),})pipe.execute()return uid# 为用户创建新动态
def create_post(uid, content):pipe = conn.pipeline(True)pipe.hget("user:%i"%(uid), 'login_name')pipe.incr("post:id")login_name, pid = pipe.execute()if not login_name:return Nonepipe.hmset("post:%i"%(pid), {'id': pid,'uid': uid,'content': content,'posted': time.time(),'user_name': login_name,})pipe.hincrby("user:%i"%(uid), 'posts')pipe.execute()return pid
read.py
#read.py
#-*- coding:utf-8 -*-import os
import sys
import time
import redis
import pprint
from code import *conn = redis.Redis()
retry_time = 0
while True:try:conn.ping()breakexcept redis.exceptions.ConnectionError:os.system("redis-server > /dev/null 2>&1 &")retry_time += 1if retry_time > 3:breakpipe = conn.pipeline(True)
pipe.delete("users", "user:id")
keys = (conn.keys("user:*") + conn.keys("followers:*") + conn.keys("following:*") +conn.keys("post:*") + conn.keys("profile:*") + conn.keys("home:*")
)
if keys:pipe.delete(*keys)
pipe.execute()# 创建测试数据
join_str = " "
for i in xrange(10):login_name = "test_user%i"%(i+1)real_name = join_str.join(login_name.split("_")).capitalize()create_user(login_name, real_name)uid = int(sys.stdin.readline().strip())print "用户 %i 关注 用户 1"%(uid)
f_result = follow(uid, 1)
print "关注结果: " + str(f_result)
printprint "测试 post 方法..."
content = "This is the first post from user 1"
pid = post(1, content)
print "创建动态: " + str(pid)
content = "NEW post from user 1!!!"
pid = post(1, content)
print "创建动态: " + str(pid)
my_profile = conn.zrevrange("profile:1", 0, -1)
print "用户 1 的动态列表: " + str(my_profile)
home_timeline = conn.zrevrange("home:%i"%(uid), 0, -1)
print "用户 %i 的主页时间线动态编号: "%(uid) + str(home_timeline)
printprint "测试 get_home_timeline 方法..."
my_home = get_home_timeline(uid)
for info in my_home:info.pop("posted", "404")
print "用户 %i 的主页时间线: "%(uid) + str(my_home)
相关文章:
使用Redis构建简易社交网站(3)-状态与信息流
目的 本文目的:实现获取主页时间线和状态推送功能。(完整代码附在文章末尾) 相关知识 在我上一篇文章 《使用Redis构建简易社交网站(2)-处理用户关系》中提到了实现用户关注和取消关注功能。 那这篇文章将教会你掌握:1&#x…...
Python,非二进制的霍夫曼编码
一般来说,霍夫曼编码是二进制的,但是非二进制的也可以。本文中,通过修改N,可以得到任意进制的霍夫曼编码。 非二进制编码的作用:例如,设计九键输入法,希望根据拼音的概率来编码,常用…...
详解—[C++数据结构]—红黑树
目录 一、红黑树的概念 编辑二、红黑树的性质 三、红黑树节点的定义 四、红黑树结构 五、红黑树的插入操作 5.1. 按照二叉搜索的树规则插入新节点 5.2、检测新节点插入后,红黑树的性质是否造到破坏 情况一: cur为红,p为红,g为黑&…...
甘草书店记:6# 2023年10月31日 星期二 「梦想从来不是一夜之间实现的」
甘草书店 今天收到甘草书店第二版装修设计平面图,与理想空间越来越近。 于我而言,每一次世俗意义上所谓的成功都不如文艺作品中表现的那样让人欢腾雀跃。当你用尽120分努力,达到了冲刺满分的实力时,得个优秀的成绩也并不意外。 …...
基于Java SSM车辆租赁管理系统
现代生活方式下,人们经常需要租赁车辆,比如婚庆、自驾游等,车辆租赁公司应运而生,车辆租赁管理系统就是借助计算机对车辆租赁情况进行全面管理。系统的主要管理对象及操作有: 车辆信息:包括车辆类型、车辆名…...
侯捷C++八部曲(一,面向对象)
头文件和类的声明 inline inline修饰函数,是给编译器的一个建议,到底是否为inline由编译器来决定,inline修饰的函数在使用时是做简单的替换,这样就避免了一些函数栈空间的使用,从能提升效率。从另一种角度看ÿ…...
《数据库系统概论》学习笔记——王珊 萨师煊
第一章 绪论 一、数据库系统概述 1.数据库的4个基本概念 (1)数据 描述事物的符号记录称为数据 (2)数据库 存放数据的仓库 (3)数据库管理系统 主要功能: (1)数据定…...
关于使用百度开发者平台处理语音朗读问题排查
错误信息:"convert_offline": false, "err_detail": "16: Open api characters limit reach 需要领取完 识别和合成都要有...
安全认证 | CISP和CISP-PTE的区别在哪里?
CISP和CISP-PTE的区别在哪里? 在国内安全信息认证体系中,虽然CISP认证与CISP-PTE认证都是中国信息安全测评中心负责颁发,均获得政府背景的认可,但二者还是有区别的。 今天就详细为大家介绍一下。 01 定义不同 ★ 注册信息安全专…...
Unity3D 导出的apk进行混淆加固、保护与优化原理(防止反编译)
目录 前言: 准备资料: 正文: 1:打包一个带有签名的apk 2:对包进行反编译 3:使用ipaguard来对程序进行加固 前言: 对于辛辛苦苦完成的apk程序被人轻易的反编译了,那就得不偿…...
C语言扫雷小游戏
以下是一个简单的C语言扫雷小游戏的示例代码: #include <stdio.h>#include <stdlib.h>#include <time.h>#define BOARD_SIZE 10#define NUM_MINES 10int main() { int board[BOARD_SIZE][BOARD_SIZE]; int num_flags, num_clicks; int …...
用取样思想一探AIX上进程性能瓶颈
本篇文章也是我在解决客户问题时的一些思路,希望对读者有用。 本文与GDB也与DBX(AIX上的调试工具)无关,只是用到了前文《GDB技巧》中的思想:取样思想 客户问题: 原始问题是磁盘被占满了,通过…...
分布式搜索引擎elasticsearch(二)
1.DSL查询文档 elasticsearch的查询依然是基于JSON风格的DSL来实现的。 1.1.DSL查询分类 Elasticsearch提供了基于JSON的DSL(Domain Specific Language)来定义查询。常见的查询类型包括: 查询所有:查询出所有数据,一般测试用。例如:match_all 全文检索(full text)查…...
Tecplot绘制涡结构(Q准则)
文章目录 目的步骤1步骤2步骤3步骤4步骤5步骤6结果 目的 Tecplot绘制涡结构(Q准则判别)并用温度进行染色 Q准则计算公式 步骤1 步骤2 步骤3 步骤4 步骤5 步骤6 结果...
Whisper
文章目录 使后感Paper Review个人觉得有趣的Log Mel spectrogram & STFT Trainingcross-attention输入cross-attention输出positional encoding数据 Decoding为什么可以有时间戳的信息 Test code 使后感 因为运用里需要考虑到时效和准确性,类似于YOLOÿ…...
Android系统分析
Android工程师进阶第八课 AMS、WMS和PMS 一、Binder通信 【Android Framework系列】第2章 Binder机制大全_android binder-CSDN博客 Android Binder机制浅谈以及使用Binder进行跨进程通信的俩种方式(AIDL以及直接利用Binder的transact方法实现)_bind…...
五、关闭三台虚拟机的防火墙和Selinux
目录 1、关闭每台虚拟机的防火墙 2、关闭每台虚拟机的Selinux 2.1 什么是SELinux...
【从零开始学习Redis | 第六篇】爆改Setnx实现分布式锁
前言: 在Java后端业务中, 如果我们开启了均衡负载模式,也就是多台服务器处理前端的请求,就会产生一个问题:多台服务器就会有多个JVM,多个JVM就会导致服务器集群下的并发问题。我们在这里提出的解决思路是把…...
Kubernetes学习笔记-Part.05 基础环境准备
目录 Part.01 Kubernets与docker Part.02 Docker版本 Part.03 Kubernetes原理 Part.04 资源规划 Part.05 基础环境准备 Part.06 Docker安装 Part.07 Harbor搭建 Part.08 K8s环境安装 Part.09 K8s集群构建 Part.10 容器回退 第五章 基础环境准备 5.1.SSH免密登录 在master01、…...
语义分割 DeepLab V1网络学习笔记 (附代码)
论文地址:https://arxiv.org/abs/1412.7062 代码地址:GitHub - TheLegendAli/DeepLab-Context 1.是什么? DeepLab V1是一种基于VGG模型的语义分割模型,它使用了空洞卷积和全连接条件随机(CRF)来提高分割…...
java设计模式学习之【建造者模式】
文章目录 引言建造者模式简介定义与用途实现方式: 使用场景优势与劣势建造者模式在spring中的应用CD(光盘)的模拟示例UML 订单系统的模拟示例UML 代码地址 引言 建造者模式在创建复杂对象时展现出其强大的能力,特别是当这些对象需…...
Spring Boot中的RabbitMQ死信队列魔法:从异常到延迟,一网打尽【RabbitMQ实战 一】
Spring Boot中的RabbitMQ死信队列魔法:从异常到延迟,一网打尽 前言第一:基础整合实现第二:处理消息消费异常第三:实现延迟消息处理第四:优雅的消息重试机制第五:异步处理超时消息第六࿱…...
nrm : 镜像源工具npm镜像切换
nrm命令 安装nrm:npm i -g nrm 查看镜像源:nrm ls,带*号的为当前使用的源 添加新镜像:nrm add [镜像源名称] <源的URL路径> 切换镜像源:nrm use [镜像源名称] 删除一个镜像源:nrm del [镜像源名称] …...
Star 10.4k!推荐一款国产跨平台、轻量级的文本编辑器,内置代码对比功能
notepad 相信大家从学习这一行就开始用了,它是开发者/互联网行业的上班族使用率最高的一款轻量级文本编辑器。但是它只能在Windows上进行使用,而且正常来说是收费的(虽然用的是pj的)。 对于想在MacOS、Linux上想使用,…...
iOS 17.2:可以修改消息提示音了
时隔2周之后,苹果今日为开发者预览版用户推送了iOS 17.2 Beta4测试版的更新,已经注册Apple Beta版软件计划的用户只需打开设置--通用--软件更新即可在线OTA升级至最新的iOS 17.2测试版。 本次更新包大小为590M左右,内部版本号为(…...
PTA 一维数组7-3出生年(本题请你根据要求,自动填充“我出生于y年,直到x岁才遇到n个数字都不相同的年份”这句话)
以上是新浪微博中一奇葩贴:“我出生于1988年,直到25岁才遇到4个数字都不相同的年份。”也就是说,直到2013年才达到“4个数字都不相同”的要求。本题请你根据要求,自动填充“我出生于y年,直到x岁才遇到n个数字都不相同的…...
【3】基于多设计模式下的同步异步日志系统-设计模式
详细介绍设计模式 单例模式 ⼀个类只能创建⼀个对象,即单例模式,该设计模式可以保证系统中该类只有⼀个实例,并提供⼀个访问它的全局访问点,该实例被所有程序模块共享。⽐如在某个服务器程序中,该服务器的配置信息存放…...
Metasploit的使用和配置
预计更新 第一章 Metasploit的使用和配置 1.1 安装和配置Metasploit 1.2 Metasploit的基础命令和选项 1.3 高级选项和配置 第二章 渗透测试的漏洞利用和攻击方法 1.1 渗透测试中常见的漏洞类型和利用方法 1.2 Metasploit的漏洞利用模块和选项 1.3 模块编写和自定义 第三章 Me…...
测试用例的设计思路
接到提测单后要做的事情: 测试准备阶段 确认提测单内包含的文件、URL地址可以访问确认需求 (迭代目标、用户故事、用户愿望、问题反馈等)确认回归测试范围、更新测试范围、新增测试范围编写测试点思维导图,过程中有问题及时进行沟通与迭代相关人员约一个…...
HCIP——交换综合实验
一、实验拓扑图 二、实验需求 1、PC1和PC3所在接口为access,属于vlan2;PC2/4/5/6处于同一网段,其中PC2可以访问PC4/5/6;但PC4可以访问PC5,不能访问PC6 2、PC5不能访问PC6 3、PC1/3与PC2/4/5/6/不在同一网段 4、所有PC通…...
it软件网站建设/巨量引擎官网
2013-全国计算机-408统考-错题、难题总结 选择题数据结构部分计算机组成原理部分综合题计组部分操作系统选择题 数据结构部分 P169 T1 -对,重点----需总结 结论:两个升序的链表要将其合并成----无论是合并升序的链表,还是降序的链表,其最坏情况下的时间复杂度都为O(n+m)<…...
深圳建立网站的公司/今天的病毒感染情况
part组员 工作 工作耗时/h明日计划工作耗时/h UI冯晓云 完善页面切换,尝试子页面设计 4 完善页面切换和子页面,修补弹窗bug 4foxit PDF Reader朱玉影 尝试添加pdf页面预览功能 4 尝试添加pdf页面预览功能 4login周以舟 …...
好域名做网站/网络推广方案七步法
一、问题由来前一段时间本人的电脑崩溃了,系统还原之后,eclipse就用不了,也找不大原因。eclipse报错原因是jvm出现问题:JVM terminated Exit code2 C:\ProgramData\Oracle\javapath\javaw.exe等发现似乎是JVM出现错误了然后输入ja…...
行业网站怎么推广/留号码的广告网站不需要验证码
假期 # 生活 # 水文 咱们继续假期第三天的日常更文,没看上篇的铁子们我把地址贴在下面。 点我 虽然是假期,但我规划已久的睡懒觉流程却是一直执行不下去。这不今天早上八点我就起床了,当然起的早不是为了“卷”,而是吃早餐。说出…...
响水做网站的价格/seo优化价格
对象的序列化主要解决的是对象状态的保存问题。这里所说的“对象状态”,其实就是指某一时刻对象所拥有的各个字段值的集合。 序列化最主要的作用有:1、在进程下次启动时读取上次保存的对象的信息 2、在不同的AppDomain或进程之间传递数据 3、在分布式应用…...
网站怎么做seo_/搜索网站的浏览器
2月8日,据外媒报道,在科技初创企业蓬勃发展的印度,有迹象表明轻松获得资金的市场环境正在发生改变。 在过去一年中的大部分时间里,印度快餐递送初创企业TinyOwl Technology Pvt.每单买卖都出现亏损,为了获得快速扩张&a…...