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来存储关注关系的更多相关文章

  1. 案例:用Redis来存储关注关系(php版)

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

  2. Redis实现关注关系

    最近使用关系型数据库实现了用户之间的关注,于是思考换一种思路,使用Redis实现用户之间的关注关系. 综合考虑了一下Redis的几种数据结构后,觉得可以用集合实现一下. 假设"我" ...

  3. 如何使用mysql存储树形关系

    最近遇到业务的一个类似文件系统的存储需求,对于如何在mysql中存储一颗树进行了一些讨论,分享一下,看看有没有更优的解决方案. 一.现有情况 首先,先假设有这么一颗树,一共9个节点,1是root节点, ...

  4. Redis 混合存储最佳实践指南

    Redis 混合存储实例是阿里云自主研发的兼容Redis协议和特性的云数据库产品,混合存储实例突破 Redis 数据必须全部存储到内存的限制,使用磁盘存储全量数据,并将热数据缓存到内存,实现访问性能与 ...

  5. 腾讯云Redis混合存储版重磅推出,万字长文助你破解缓存难题!

    导语 | 缓存+存储的系统架构是目前常见的系统架构,缓存层负责加速访问,存储层负责存储数据.这样的架构需要业务层或者是中间件去实现缓存和存储的双写.冷热数据的交换,同时还面临着缓存失效.缓存刷脏.数据 ...

  6. 快手推荐系统及 Redis 升级存储

    快手推荐系统及 Redis 升级存储  借傲腾 补上 DRAM 短板 内容简介: 作为短视频领域的领先企业,快手需要不断导入更先进的技术手段来调整和优化其系统架构,以应对用户量和短视频作品数量的爆炸式 ...

  7. redis数据存储的细节

    redis是一个K-V NoSql非关系型数据库,redis有物种数据类型,分别是String,Hash,list,set,zset:这五种类型都是针对K-V中的V设计的. 1.总体介绍:关于redi ...

  8. redis数据结构存储SDS设计细节(redis的设计与实现笔记)

    redis虽说是用C语言开发的,但是redis考虑了性能.安全性.效率性.功能等要,redis底层存储字符串实现,自己实现了名为简单动态字符串(Simple dynamic string)简称SDS的 ...

  9. Redis和Memcache的关系

    转自: http://blog.163.com/sun_jian_zhang/blog/static/187804041201310795917333/ 1. Redis中,并不是所有的数据都一直存储 ...

随机推荐

  1. MYSQL优化优化再优化!

    1.数据库设计和表创建时就要考虑性能 2.sql的编写需要注意优化 3.分区 4.分表 5.分库 .数据库设计和表创建时就要考虑性能 mysql数据库本身高度灵活,造成性能不足,严重依赖开发人员能力. ...

  2. SpringBoot启动器详解pom.xml

    Spring Boot应用启动器基本的一共有44种,具体如下: 1)spring-boot-starter 这是Spring Boot的核心启动器,包含了自动配置.日志和YAML. 2)spring- ...

  3. vue $options 获取自定义属性

    说明: https://cn.vuejs.org/v2/api/#vm-options 用于当前 Vue 实例的初始化选项.需要在选项中包含自定义属性时会有用处. element-ui代码中经常定义组 ...

  4. Oracle Data Integrator学习资料

    http://docs.oracle.com/middleware/1213/odi/index.html https://docs.oracle.com/middleware/1213/core/O ...

  5. oracle 根据字段查询重复数据

      1.情景展示 由上图可知,APPUSERID字段和VIRTUAL_CARDID字段存在一对多的关系,如何将重复的APPUSERID字段的数据查询出来呢? 2.原因分析 先查出重复的APPUSERI ...

  6. 【Windows】XShell中使用小键盘和ALT键(作Meta键),使BackSpace正常

    小键盘: 打开终端的Session属性,VT模式,初始数字键盘模式,设置为普通 ALT键: 打开终端的Session属性,元(Meta)键仿真,将ALT用作Meta键 BackSpace: 打开终端的 ...

  7. CPLSetErrorHandlerEx函数Bug

    CPLSetErrorHandlerEx(gdal/gdal/port/cpl_error.cpp,当前github中代码)当前函数实现如下 CPLErrorHandler CPL_STDCALL C ...

  8. Centos6.5卸载图形化

    问题描述: Centos6.5想运行在非图形化状态,减小系统资源的开销!提升服务器性能....... 问题解决: 01.切换运行模式,变相实现非图形化运行 多用户模式 init 图形化模式 init ...

  9. Android(4.0.3+): Service, AsyncTask, 定时任务和UI通信

    Service使用AlarmManager实现后台定时任务 在Android 4.0.3版本中, 使用AlarmManager实现后台定时任务是比较好的方案, 其实现机制, 是利用Service的 o ...

  10. Ubuntu18.04 运行 Gradle 4.9

    简介 Gradle是一个基于Apache Ant和Apache Maven的项目自动化构建工具, 使用一种基于Groovy的特定领域语言(domain-specific language DSL)来声 ...