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标准写法及其他常见问题

    /* Navicat MySQL Data Transfer Source Server : localhost_3306 Source Server Version : 50549 Source H ...

  2. spring mvc防止表单重复提交的代码片段

    1.定义一个token接口 package com.bigbigrain.token; import java.lang.annotation.Documented; import java.lang ...

  3. Spring Boot 启动载入数据 CommandLineRunner

    实际应用中,我们会有在项目服务启动的时候就去载入一些数据或做一些事情这种需求. 为了解决这种问题.Spring Boot 为我们提供了一个方法.通过实现接口 CommandLineRunner 来实现 ...

  4. python之模块filecmp(文件/目录比较)

    # -*- coding: utf-8 -*- #python 27 #xiaodeng #python之模块filecmp(文件/目录比较) #用于比较文件及文件夹的内容.他是轻量级的工具.可以做一 ...

  5. 完完全全彻底删除VMware_Workstation

    vmware-workstation,卸载不干净.bat脚本自动处理dll.注册的表垃圾 Download https://pan.baidu.com/s/1dmrOs3rkR8cX5b0vTUOxH ...

  6. Spring Cloud开发实践 - 03 - 接口实现和下游调用

    接口实现 Scot Commons Impl 接口实现模块 scot-commons-impl, 一方面实现了 scot-commons-api 的接口, 一方面将自己暴露为 REST 服务. 有4个 ...

  7. Heroku免费版限制

    SLEEPS AFTER 30 MINS OF INACTIVITY   30分钟无人访问就休眠 Verified accounts come with a monthly pool of 1000 ...

  8. socket 995 错误 boost

    这个错误的中文解释是:由于线程退出或应用程序请求,已中止 I/O 操作. 最近几天学习boost asio 在抄官方的一个实例代码时遇到 了,这个错误搞了我三天才解决,就是在一行代码中少了一个 s 所 ...

  9. 转 java实现截图

    转自 http://www.zhenhua.org/article.asp?id=382 可以直接运行! import java.awt.Dimension; import java.awt.Rect ...

  10. 优化 App 的启动时间

    这是一篇 WWDC 2016 Session 406 的学习笔记,从原理到实践讲述了如何优化 App 的启动时间. App 运行理论 main() 执行前发生的事 Mach-O 格式 虚拟内存基础 M ...