做淘寶優(yōu)惠券推廣網(wǎng)站搜索數(shù)據(jù)
目的
本文目的:實(shí)現(xiàn)獲取主頁時(shí)間線和狀態(tài)推送功能。(完整代碼附在文章末尾)
相關(guān)知識(shí)
在我上一篇文章 《使用Redis構(gòu)建簡(jiǎn)易社交網(wǎng)站(2)-處理用戶關(guān)系》中提到了實(shí)現(xiàn)用戶關(guān)注和取消關(guān)注功能。
那這篇文章將教會(huì)你掌握:1
.redis
基本命令,2
.python
基本命令。
redis基本命令
zadd:將成員加入到有序集合中,并確保其在正確的位置上。
conn = redis.Redis()
conn.zadd("testzset", "member2", 3)
conn.zadd("testzset", "member1", 2)
conn.zadd("testzset", "member3", 1)
執(zhí)行后:
member3
member1
member2
執(zhí)行結(jié)果:1
,1
,1
zrange:返回有序集合中指定區(qū)間內(nèi)的成員。
conn = redis.Redis()
conn.zrange("testzset", 0, 1)
執(zhí)行結(jié)果:['member3', 'member1']
zrevrange:按分值遞減的順序返回有序集合中指定區(qū)間內(nèi)的成員。
conn = redis.Redis()
conn.zrevrange("testzset", 0, -1)
執(zhí)行結(jié)果:['member2', 'member1', 'member3']
hgetall:返回哈希表中所有的域-值對(duì)。
conn = redis.Redis()
conn.hgetall("testhash")
執(zhí)行結(jié)果:{'field1': '2'}
hget:從哈希中獲取指定域的值。
conn = redis.Redis()
conn.hget("testhash", "field1")
執(zhí)行結(jié)果:2
pipeline:將多條命令按照先后順序放進(jìn)一個(gè)隊(duì)列中,一般配合execute一同使用,原子性(atomic)地執(zhí)行隊(duì)列里的命令。
conn = redis.Redis()
pipe = conn.pipeline(True) # 事務(wù)開始
pipe.incr("counter")
pipe.incr("counter")
pipe.incr("counter")
pipe.execute() # 事務(wù)執(zhí)行
執(zhí)行結(jié)果:[1, 2, 3]
,通過下標(biāo)即可獲取對(duì)應(yīng)命令的執(zhí)行結(jié)果。
python基本命令
使用格式化拼接字符串:
"My name is %s, I'm %i years old"%('educoder', 2)
執(zhí)行結(jié)果:"My name is educoder, I'm 2 years old"
將字符串轉(zhuǎn)換為浮點(diǎn)數(shù):
float("1.23")
執(zhí)行結(jié)果:1.23
實(shí)戰(zhàn)例題
編寫 get_home_timeline(uid)
函數(shù),實(shí)現(xiàn)獲得主頁時(shí)間線的功能,具體參數(shù)與要求如下:
- 方法參數(shù)
uid
為要獲取主頁時(shí)間線的用戶編號(hào); - 獲取動(dòng)態(tài)編號(hào)的實(shí)現(xiàn):從存儲(chǔ)用戶主頁時(shí)間線的有序集合
home:{uid}
中按照分值遞減的順序取出所有成員; - 獲取動(dòng)態(tài)詳情的實(shí)現(xiàn):遍歷動(dòng)態(tài)編號(hào),使用事務(wù)一次性獲取每個(gè)動(dòng)態(tài)編號(hào)對(duì)應(yīng)動(dòng)態(tài)詳情哈希鍵
post:{pid}
的所有域-值對(duì); - 返回主頁時(shí)間線的實(shí)現(xiàn):返回事務(wù)執(zhí)行的結(jié)果。
編寫 post(uid, content)
函數(shù),實(shí)現(xiàn)發(fā)布動(dòng)態(tài)并將動(dòng)態(tài)推送給粉絲的功能,具體參數(shù)與要求如下:
- 方法參數(shù)
uid
為要發(fā)布動(dòng)態(tài)的用戶編號(hào),content
為要發(fā)布的動(dòng)態(tài)內(nèi)容; - 發(fā)布動(dòng)態(tài)的實(shí)現(xiàn):調(diào)用第一關(guān)中實(shí)現(xiàn)的
create_post
方法,并接收返回的動(dòng)態(tài)編號(hào),若發(fā)布失敗,則取消發(fā)布,返回None
; - 獲取發(fā)布時(shí)間的實(shí)現(xiàn):從新發(fā)布的動(dòng)態(tài)編號(hào)對(duì)應(yīng)的動(dòng)態(tài)詳情哈希鍵
post:{pid}
中獲取posted
域; - 更新個(gè)人主頁的實(shí)現(xiàn):將新發(fā)布的動(dòng)態(tài)編號(hào)存儲(chǔ)到個(gè)人主頁有序集合鍵
profile:{uid}
中,分值為轉(zhuǎn)為浮點(diǎn)數(shù)后的發(fā)布時(shí)間; - 更新粉絲主頁時(shí)間線的實(shí)現(xiàn):遍歷用戶的粉絲列表
followers:{uid}
,將新發(fā)布的動(dòng)態(tài)編號(hào)存儲(chǔ)到每個(gè)粉絲的主頁時(shí)間線的有序集合home:{follower_id}
中,分值為轉(zhuǎn)為浮點(diǎn)數(shù)后的發(fā)布時(shí)間; - 返回發(fā)布結(jié)果的實(shí)現(xiàn):返回新發(fā)布的動(dòng)態(tài)編號(hào)。
測(cè)試說明
測(cè)試輸入:4
;
預(yù)期輸出:
用戶 4 關(guān)注 用戶 1
關(guān)注結(jié)果: True測(cè)試 post 方法...
創(chuàng)建動(dòng)態(tài): 1
創(chuàng)建動(dòng)態(tài): 2
用戶 1 的動(dòng)態(tài)列表: ['2', '1']
用戶 4 的主頁時(shí)間線動(dòng)態(tài)編號(hào): ['2', '1']測(cè)試 get_home_timeline 方法...
用戶 4 的主頁時(shí)間線: [{'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()# 獲得主頁時(shí)間線
def get_home_timeline(uid, page=1, count=30):# 請(qǐng)?jiān)谙旅嫱瓿梢蟮墓δ?********* 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 *********## 發(fā)布動(dòng)態(tài)并將動(dòng)態(tài)推送給粉絲
def post(uid, content):# 請(qǐng)?jiān)谙旅嫱瓿梢蟮墓δ?********* 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 *********## 關(guān)注用戶
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# 取消關(guān)注
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# 創(chuàng)建新用戶
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# 為用戶創(chuàng)建新動(dòng)態(tài)
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()# 創(chuàng)建測(cè)試數(shù)據(jù)
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 關(guān)注 用戶 1"%(uid)
f_result = follow(uid, 1)
print "關(guān)注結(jié)果: " + str(f_result)
printprint "測(cè)試 post 方法..."
content = "This is the first post from user 1"
pid = post(1, content)
print "創(chuàng)建動(dòng)態(tài): " + str(pid)
content = "NEW post from user 1!!!"
pid = post(1, content)
print "創(chuàng)建動(dòng)態(tài): " + str(pid)
my_profile = conn.zrevrange("profile:1", 0, -1)
print "用戶 1 的動(dòng)態(tài)列表: " + str(my_profile)
home_timeline = conn.zrevrange("home:%i"%(uid), 0, -1)
print "用戶 %i 的主頁時(shí)間線動(dòng)態(tài)編號(hào): "%(uid) + str(home_timeline)
printprint "測(cè)試 get_home_timeline 方法..."
my_home = get_home_timeline(uid)
for info in my_home:info.pop("posted", "404")
print "用戶 %i 的主頁時(shí)間線: "%(uid) + str(my_home)