案例:用Redis来存储关注关系

标签: Redis follow 关注 好友关系 | 发表时间:2011-08-28 17:20 | 作者:nosqlfan Wang Dong
出处:http://blog.nosqlfan.com

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)

来源:blog.meltingice.net

相关文章:
用Redis存储好友关系-python版
Redis源码分析系列文章
redis 适用场景与实现
Redis之七种武器
django-redis-cache:用Redis作django的缓存层
无觅

相关 [redis 关系] 推荐:

案例:用Redis来存储关注关系

- Wang Dong - NoSQLFan
Redis提供了丰富的数据类型,比起关系型数据库或者简单的Key-Value存储(比如Memcached)来,Redis的数据模型与实际应用的数据模型更相近. 比如下面说到的好友关系的存储,原作者使用了Redis的 Sets(集合)数据结构. 具体存储方式如下:对于每一个用户,其关注关系存储两份列表,一份为此用户关注的人的UID列表,另一份为此用户粉丝的UID列表,这两个列表都使用Sets(集合).

用Redis来存储关注关系(java实现)

- - ITeye博客
//一个接口UserService.java //一个接口的实现UserServiceImpl.java //两个采用Jedis的客户端测试类FollowTestMain.java,IsFollowTestMain.java. //UserService.java接口如下 package com.redis.test; import java.util.Set; public interface UserService {.

Redis 负载监控——redis-monitor

- - ITeye资讯频道
redis-monitor是一个Web可视化的 redis 监控程序. 使用 Flask 来开发的,代码结构非常简单,适合移植到公司内网使用. redis 服务器信息,包括 redis 版本、上线时间、 os 系统信息等等. 实时的消息处理信息,例如处理 command 数量、连接总数量等. 内存占用、 cpu 消耗实时动态图表.

Redis 起步

- - 博客园_首页
Rdis和JQuery一样是纯粹为应用而产生的,这里记录的是在CentOS 5.7上学习入门文章:. Redis是一个key-value存储系统. 和Memcached类似,但是解决了断电后数据完全丢失的情况,而且她支持更多无化的value类型,除了和string外,还支持lists(链表)、sets(集合)和zsets(有序集合)几种数据类型.

redis 配置

- - 谁主沉浮
# 当配置中需要配置内存大小时,可以使用 1k, 5GB, 4M 等类似的格式,其转换方式如下(不区分大小写). # 内存配置大小写是一样的.比如 1gb 1Gb 1GB 1gB. # daemonize no 默认情况下,redis不是在后台运行的,如果需要在后台运行,把该项的值更改为yes. # 当redis在后台运行的时候,Redis默认会把pid文件放在/var/run/redis.pid,你可以配置到其他地址.

Cassandra代替Redis?

- - Tim[后端技术]
最近用Cassandra的又逐渐多了,除了之前的360案例,在月初的QCon Shanghai 2013 篱笆网也介绍了其使用案例. 而这篇 百万用户时尚分享网站feed系统扩展实践文章则提到了Fashiolista和Instagram从Redis迁移到Cassandra的案例. 考虑到到目前仍然有不少网友在讨论Redis的用法问题,Redis是一个数据库、内存、还是Key value store?以及Redis和memcache在实际场景的抉择问题,因此简单谈下相关区别.

redis 部署

- - CSDN博客云计算推荐文章
一、单机部署 tar xvf redis-2.6.16.tar.gz cd redis-2.6.16 make make PREFIX=/usr/local/redis install  #指定安装目录为/usr/local/redis,默认安装安装到/usr/local/bin. # chkconfig: 2345 80 10       #添加redhat系列操作系统平台,开机启动需求项(运行级别,开机时服务启动顺序、关机时服务关闭顺序) # description:  Starts, stops redis server.

nagios 监控redis

- - C1G军火库
下载check_redis.pl. OK: REDIS 2.6.12 on 192.168.0.130:6379 has 1 databases (db0) with 49801 keys, up 3 days 14 hours - connected_clients is 1, blocked_clients is 0 | connected_clients=1 blocked_clients=0.

转 redis vs memcached

- - 数据库 - ITeye博客
传统MySQL+ Memcached架构遇到的问题.   实际MySQL是适合进行海量数据存储的,通过Memcached将热点数据加载到cache,加速访问,很多公司都曾经使用过这样的架构,但随着业务数据量的不断增加,和访问量的持续增长,我们遇到了很多问题:.   1.MySQL需要不断进行拆库拆表,Memcached也需不断跟着扩容,扩容和维护工作占据大量开发时间.

Redis优化

- - 数据库 - ITeye博客
键名:尽量精简,但是也不能单纯为了节约空间而使用不易理解的键名. 键值:对于键值的数量固定的话可以使用0和1这样的数字来表示,(例如:male/female、right/wrong). 当业务场景不需要数据持久化时,关闭所有的持久化方式可以获得最佳的性能,不过一般都要持久化比较安全,而且是快照和aof同时使用比较安全.