• 案例:用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)

    来源:blog.meltingice.net

  • 相关阅读:
    Linux基础命令(一)
    You've made choice
    protege推理
    字符编码
    第二次作业
    数据类型-集合set
    数据类型-元组&字典
    数据类型-列表
    数据类型-数值&字符串
    流程控制之for循环
  • 原文地址:https://www.cnblogs.com/qq78292959/p/2892799.html
Copyright © 2020-2023  润新知