用Redis来存储关注关系

Redis提供了丰富的数据类型,比起关系型数据库或者简单的Key-Value存储(比如Memcached)来,Redis的数据模型与实际应用的数据模型更相近。比如下面说到的好友关系的存储,原作者使用了Redis的 Sets(集合)数据结构。

具体存储方式如下:对于每一个用户,其关注关系存储两份列表,一份为此用户关注的人的UID列表,另一份为此用户粉丝的UID列表,这两个列表都使用Sets(集合)。比如对于用户ID为123的用户,graph:user:123:following 保存的是其关注人的列表,graph:user:1:followed_by 保存的是关注他的人的列表。

下面是一个PHP代码的关注关系类,包括了常规的关注关系操作查询等方法,具体可看注释:

<?

/*

* This example would probably work best if you're using

* an MVC framework, but it can be used standalone as well.

*

* This example also assumes you are using Predis, the excellent

* PHP Redis library available here:

* https://github.com/nrk/predis

*/

class UserNode {

// The user's ID, probably loaded from MySQL

private $id;

// The redis server configuration

private $redis_config = array(

array('host' => 'localhost', 'port' => 6379 )

);

// Stores the redis connection resource so that

// we only need to connect to Redis once

private $redis;

public function __construct($userID) {

$this->id = $userID;

}

private function redis() {

if (!$this->redis) {

$this->redis = new Predis\Client($redis_config);

}

return $this->redis;

}

/*

* Makes this user follow the user with the given ID.

* In order to stay efficient, we need to make a two-way

* directed graph. This means when we follow a user, we also

* say that that user is followed by this user, making a forward

* and backword directed graph.

*/

public function follow($user) {

$this->redis()->sadd("graph:user:{$this->id}:following", $user);

$this->redis()->sadd("graph:user:$user:followed_by", $this->id);

}

/*

* Makes this user unfollow the user with the given ID.

* First we check to make sure that we are actually following

* the user we want to unfollow, then we remove both the forward

* and backward references.

*/

public function unfollow($user) {

if ($this->is_following()) {

$this->redis()->srem("graph:user:{$this->id}:following", $user);

$this->redis()->srem("graph:user:$user:followed_by", $this->id);

}

}

/*

* Returns an array of user ID's that this user follows.

*/

public function following() {

return $this->redis()->smembers("graph:user:{$this->id}:following");

}

/*

* Returns an array of user ID's that this user is followed by.

*/

public function followed_by() {

return $this->redis()->smembers("graph:user:{$this->id}:followed_by");

}

/*

* Test to see if this user is following the given user or not.

* Returns a boolean.

*/

public function is_following($user) {

return $this->redis()->sismember("graph:user:{$this->id}:following", $user);

}

/*

* Test to see if this user is followed by the given user.

* Returns a boolean.

*/

public function is_followed_by($user) {

return $this->redis()->sismember("graph:user:{$this->id}:followed_by", $user);

}

/*

* Tests to see if the relationship between this user and the given user is mutual.

*/

public function is_mutual($user) {

return ($this->is_following($user) && $this->is_followed_by($user));

}

/*

* Returns the number of users that this user is following.

*/

public function follow_count() {

return $this->redis()->scard("graph:user:{$this->id}:following");

}

/*

* Retuns the number of users that follow this user.

*/

public function follower_count() {

return $this->redis()->scard("graph:user:{$this->id}:followed_by");

}

/*

* Finds all users that the given users follow in common.

* Returns an array of user IDs

*/

public function common_following($users) {

$redis = $this->redis();

$users[] = $this->id;

$keys = array();

foreach ($users as $user) {

$keys[] = "graph:user:{$user}:following";

}

return call_user_func_array(array($redis, "sinter"), $keys);

}

/*

* Finds all users that all of the given users are followed by in common.

* Returns an array of user IDs

*/

public function common_followed_by($users) {

$redis = $this->redis();

$users[] = $this->id;

$keys = array();

foreach ($users as $user) {

$keys[] = "graph:user:{$user}:followed_by";

}

return call_user_func_array(array($redis, "sinter"), $keys);

}

}

下面是使用这个类来操作关注关系的例子:

<?

// create two user nodes, assume for this example

// they're users with no social graph entries.

$user1 = UserNode(1);

$user2 = UserNode(2);

$user1->follows(); // array()

// add some followers

$user1->follow(2);

$user1->follow(3);

// now check the follow list

$user1->follows(); // array(2, 3)

// now we can also do:

$user2->followed_by(); // array(1)

// if we do this...

$user2->follow(3);

// then we can do this to see which people users #1 and #2 follow in common

$user1->common_following(2); // array(3)

下面关于Redis的文章您也可能喜欢,不妨参考下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/0777fda5290c5bdd8225fd513e3bb4cc.html