logo

redis与MongoDB和关系数据库最大的不同是没有表的概念,所有东西都是key-value的,但在一些场景用得好是非常合适自然的。

用户信息

hash

127.0.0.1:6379> set next_user_id 999
OK
127.0.0.1:6379> INCR next_user_id 
(integer) 1000
127.0.0.1:6379> HMSET user:1000 username ccj password xxxxxx
OK
127.0.0.1:6379> hgetall user:1000
1) "username"
2) "ccj"
3) "password"
4) "xxxxxx"

有时候,需要通过用户名查找用户id, 可以加上

127.0.0.1:6379> HSET users ccj 1000
(integer) 1
127.0.0.1:6379> hget users ccj
"1000"

关注,粉丝

hash sets: 关注列表, 粉丝列表, 双向关注列表(key-value(field), 排序)
查询用户关注列表:hgetAll uid.following ,then sort
查询用户粉丝列表:hgetAll uid.follower,then sort
查询用户双向关注列表:hgetAll uid.bifollow,then sort
判断两个用户关系:hget uidA.following uidB && hget uidB.following uidA

计数

string(counter): 微博数, 粉丝数
一个计数器,至少应该拥有以下四个操作:
增加数值,减少数值,清零,查看当前数值
计数器可以用以下两种方式实现:

String类函数,INCR,INCRBY,DECR,DECRBY,还有GET和SET。

 key: topic:<topic_id>:views
 value: view count (integer)

Hash类函数,HINCRBY,HSET和HGET。

  key: topic:views
  value: hash
    hash key: <topic_id>
    hash value: view count (integer)

TopN 排行榜,热门,

sort sets(自动排序): TopN, 热门微博等, 自动排序
list 最新项目列表,用LPUSH + LTRIM,确保只取出最新的N条项目

订阅推送

lists(queue): push/sub提醒,…

点赞

hash + set,无序,Hasht里保存Set的key

$redis->hset($hashKey, $userKey, $setKey);
$redis->sAdd($setKey, "1");
$redis->sAdd($setKey, "2");
$redis->sAdd($setKey, "3");

sorted set,有序

$redis->ZADD("t:$tid:liked", time(), $uid); //$tid 为你的微博ID, $uid 为你的点赞人的UID

//取出点赞的人(支持按照点赞时间来排序的哦:)
$uids = $redis->ZREVRANGE("t:$tid:liked", $offset, $max, TRUE); //倒序取值
$uids = $redis->ZRANGE("t:$tid:liked", $offset, $max, TRUE); //顺序取值

//$offset 和 $max 这样来算
$pagesize = 20;
$offset = ($page > 1) ? ($page - 1) * $pagesize : 0;
$max = ($page * $pagesize) - 1;

//一次性取出所有的这样取.
$total = $redis->ZCARD("t:$tid:liked");
$uids = $redis->ZREVANGE("t:$tid:liked", 0, $total - 1, TRUE);

//拿到的$uids 是一个array 哦..

//判断一个用户是否点赞了这一来哦
$redis->ZSCORE("t:$tid:liked", $uid);
//取消赞这样来
$redis->ZREM("t:$tid:liked", $uid);

//批量取消某短时间内的点赞这样操作
$redis->ZREMRANGEBYSCORE("t:$tid:liked", $start_timestamp, $end_timestamp);

时间线(timeline)

一个时间线对象最少有两个属性
时间值
数据内容
针对时间线对象的操作通常都是一些范围型的操作:比如求某个时间点起到另一个时间点内的所有数据,或者是统计某个时间点起到另一个时间点内的数据数目,等等。
在Redis中我们可以用sorted set存储时间线。
ZADD tweet 1313981227.681918 "hello"

TAG系统

使用set
给news加标签

127.0.0.1:6379> sadd news:1000:tags a b c 
(integer) 3

查看

127.0.0.1:6379> smembers news:1000:tags
1) "c"
2) "a"
3) "b"

为了查找反向关系,查所有tag为a的news id.

127.0.0.1:6379> sadd tag:a:news 1000
(integer) 1
127.0.0.1:6379> sadd tag:b:news 1000
(integer) 1
127.0.0.1:6379> sadd tag:c:news 1000
(integer) 1
127.0.0.1:6379>  smembers tag:a:news
1) "1000"

另外还可以通过sinter,sdiff,sunion查找交叉并集。

127.0.0.1:6379>  sinter tag:a:news tag:b:news
1) "1000"

当然Tag在MongoDB里的设计也类似,
加标签,存标签到数组
查找对应标签的news可以直接用$all操作符,还可以类似建一个tagnews集合存放每个tag对应的所有news id(放数组)

> db.news.insert({title:"hi"})
WriteResult({ "nInserted" : 1 })
>  db.news.findOne()
{ "_id" : ObjectId("563f0f4f419c168c2e7f5cdc"), "title" : "hi" }
> db.news.update({"_id" : ObjectId("563f0f4f419c168c2e7f5cdc")},{$set:{tags:["a","b","c"]}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.news.findOne()
{
    "_id" : ObjectId("563f0f4f419c168c2e7f5cdc"),
    "title" : "hi",
    "tags" : [
        "a",
        "b",
        "c"
    ]
}
>  db.news.find({tags:{$all:["a"]}})
{ "_id" : ObjectId("563f0f4f419c168c2e7f5cdc"), "title" : "hi", "tags" : [ "a", "b", "c" ] }

如果单独存放tag关系,后续有其他news的可以push到数组

> db.tagnews.insert({tag:"a",newsid:[ObjectId("563f0f4f419c168c2e7f5cdc")]})
WriteResult({ "nInserted" : 1 })
> db.tagnews.insert({tag:"b",newsid:[ObjectId("563f0f4f419c168c2e7f5cdc")]})
WriteResult({ "nInserted" : 1 })
>  db.tagnews.insert({tag:"c",newsid:[ObjectId("563f0f4f419c168c2e7f5cdc")]})
WriteResult({ "nInserted" : 1 })
> db.tagnews.find()
{ "_id" : ObjectId("563f1082419c168c2e7f5cdd"), "tag" : "a", "newsid" : [ ObjectId("563f0f4f419c168c2e7f5cdc") ] }
{ "_id" : ObjectId("563f108e419c168c2e7f5cde"), "tag" : "b", "newsid" : [ ObjectId("563f0f4f419c168c2e7f5cdc") ] }
{ "_id" : ObjectId("563f1096419c168c2e7f5cdf"), "tag" : "c", "newsid" : [ ObjectId("563f0f4f419c168c2e7f5cdc") ] }

ccj 于 2015-11-08 17:20 修改
0 回复
需要 登录 后方可回复, 如果你还没有账号你可以 注册 一个帐号。