文档章节

用Redis实现微博关注关系

jockchou
 jockchou
发布于 2015/07/02 16:32
字数 1377
阅读 7809
收藏 242

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

用Redis实现微博关注关系的分析


关注关系产生的四种关系状态

  • 关注
  • 粉丝
  • 双向关注(互粉)
  • 无关系

需求分析

在微博中,每一个用户都会有一个关注列表,一个粉丝列表。用户可以查看自己的关注,粉丝列表,也可以查看别人的关注,粉丝列表。并且,要展示列表里每个人与当前查看者的关注状态。状态的可能性就是上面讲到得四种关系状态。

问题可以分两种情况来看:

  1. 看自己的关注,粉丝列表
  2. 看别人的关注,粉丝列表

看自己的关注,粉丝列表:

这种情况相对简单一点。比如看自己的关注列表,列表里的人的与自己的关系状态不可能是“无关系”和“粉丝”。只可能是“关注”和“双向关注”。同样,粉丝列表也只有两种状态。

看别人的关注,粉丝列表:

这是最复杂的情况,假如看别人关注列表,列表里的人和自己可能有上述全部四种关系状态。

从集合的图来分析

关注关系集合图

如上图所示。左边的圆表示用户的关注列表,右边的圆表示粉丝列表,下边的圆表示的是要查看的列表(集合)。分别用follow, fans, find来表明这三个集合。

当查看自己的列表时,其实表示find集合是上面集合中某一个的子集。例如查看自己粉丝,表示find是fans的子集,查看自己的关注,表示find是follow的子集。

查看别人的列表时,此时图中产生了三个集合的交集。要查询集合中的用户可能是在你的粉丝,关注集合中,也可能不在。就是说可能是任何一种关系状态,问题的根本就是,我们要计算出每一个用户与当前用户的关系状态。要求解四种关系状态,我们必然要求出图中下部分的三个小交集。

  • 要查询的集合与我的互粉交集
  • 要查询的集合与我的关注交集
  • 要查询的集的与我的粉丝交集

不在这三个小交集中的用户就是无关系状态的用户。

假如我们采用如下一套命名:

关注集合
follow:userID

粉丝集合
fans:userID

互粉集合(临时)
fofa:userID

要查询的集合(临时)
find:userID

要查询的集合与我的关注交集(临时)
find_inter_follow:userID

要查询的集的与我的粉丝交集(临时)
find_inter_fans:userID

要查询的集合与我的互粉交集(临时)
find_inter_fofa:userID

find中其他就是未关注

使用Sorted Set存储关系

score用来存储关注的时间,每个用户存储两个集合。follow:userID存储用户的关注,fans:userID存储用户的粉丝。于是我们可以设计一个函数来求出这些状态的集合。

函数返回:

"findSet" => $findSet, //要查询的集合
"fofaSet" => $fofaSet, //互粉的集合
"findInterFollowSet" => $findInterFollowSet, //要查询的集合与我的关注交
"findInterFansSet" => $findInterFansSet //要查询的集的与我的粉丝交

求出以上四个集合,就可以进行关系状态判断,先判断是否互粉,如果不是互粉,再判断是否是我关注的,如果不是,再判断是否是我的粉丝。如果都不是就是无关系。这样就能把状态求出来了。

/*
* userID:当前用户id
* targetUserID: 被查看的人的id
* findType: 查看的是哪个列表
* findStart: 分页查看的列表开始的位置
* findEnd: 分页查看的列表结束的位置
*/
function getChunkSets($redis, $userID, $targetUserID, $findType, $findStart, $findEnd) {

		$fansKey = "fans:" . $userID;
		$followKey = "follow:" . $userID;
		$findKey = "find:" . $userID;

		$targetKey =  $findType. ":" . $targetUserID;
		$fofaKey = "find_inter_fofa:" . $userID;

		$findInterFollowKey = "find_inter_follow:" . $userID;
		$findInterFansKey = "find_inter_fans:" . $userID;

		//找出要查询的集合元素
		$findSet = $redis->zRevRange($targetKey, $findStart, $findEnd, TRUE);

		//要查询的集合与我的关注交
		$findInterFollowSet = array();

		//要查询的集的与我的粉丝交
		$findInterFansSet = array();

		//先清掉临时集合
		$redis->del($findKey);

		$redis->del($fofaKey);
		$redis->del($findInterFollowKey);
		$redis->del($findInterFansKey);


		//存起来
		foreach ($findSet as $uid => $score) {
			$redis->zAdd($findKey, $score, $uid);
		}

		//求互粉集合
		if ($userID != $targetUserID) { //看别人
			$redis->zInter($fofaKey, array($findKey, $fansKey, $followKey));

			/*
			 * 如果不是看自己的列表,还要求
			 * 1: 要查询的集合与我的关注交
			 * 2: 要查询的集的与我的粉丝交
			 */
			$redis->zInter($findInterFollowKey, array($findKey, $followKey));
			$redis->zInter($findInterFansKey, array($findKey, $fansKey));

			$findInterFollowSet = $redis->zRevRange($findInterFollowKey, 0, -1);
			$findInterFansSet = $redis->zRevRange($findInterFansKey, 0, -1);

		} else {
			if ($findType == "fans") { //自己看粉丝列表
				$redis->zInter($fofaKey, array($findKey, $followKey));
			} else if ($findType == "follow") { //看自己关注列表
				$redis->zInter($fofaKey, array($findKey, $fansKey));
			}
		}

		//互粉集合
		$fofaSet = $redis->zRevRange($fofaKey, 0, -1);

		return array(
			"findSet" => $findSet, //要查询的集合
			"fofaSet" => $fofaSet, //互粉的集合
			"findInterFollowSet" => $findInterFollowSet, //要查询的集合与我的关注交
			"findInterFansSet" => $findInterFansSet //要查询的集的与我的粉丝交
		);
	}

以上函数已经求出了所需要的集合,然后就是关系状态判断了。

/*
* isSelf: 是否查看自己的列表
* findType: 查看的是粉丝还是关注列表 1: 关注, 2: 粉丝
* userInfoArr: 用户详细信息数组
*/
function getUserInfoList($isSelf, $findType, $userInfoArr, $findSet, $fofaSet, $interFansSet, $interFollowSet) {

		$userInfoList = array();

		foreach($findSet as $userID => $favoTime) {
			if(!in_array($userID, array_keys($userInfoArr))) continue;

			$userInfo = new UserInfo($userInfoArr[$userID]);
			$userInfo = $userInfo->format();

			if(in_array($userID, $fofaSet)){
				$userInfo['favoFlag'] = 3; //互相关注
			} else {
				if($isSelf) {
					$userInfo['favoFlag'] = $findType;
				} else {
					if(in_array($userID, $interFansSet)) {
						$userInfo['favoFlag'] = 2; //我的粉丝
					} else if(in_array($userID, $interFollowSet)) {
						$userInfo['favoFlag'] = 1; //我的关注
					} else{
						$userInfo['favoFlag'] = 0; //无关系
					}
				}
					
			}

			$userInfo['favoTime'] = $favoTime;
			array_push($userInfoList, $userInfo);
		}

		return $userInfoList;
	}

© 著作权归作者所有

jockchou

jockchou

粉丝 28
博文 39
码字总数 29164
作品 1
深圳
高级程序员
私信 提问
加载中

评论(25)

gaodaojiang
gaodaojiang
。。。
jockchou
jockchou 博主

引用来自“终曲”的评论

很有想法,不过为了性能,我们实际的处理是很暴力的

引用来自“jockchou”的评论

可以分享一下你们的实现方式

引用来自“终曲”的评论

补充一句,那文章作者不是我,而且已经离职了
这个我看过。
终曲
终曲

引用来自“终曲”的评论

很有想法,不过为了性能,我们实际的处理是很暴力的

引用来自“jockchou”的评论

可以分享一下你们的实现方式
补充一句,那文章作者不是我,而且已经离职了
终曲
终曲

引用来自“终曲”的评论

很有想法,不过为了性能,我们实际的处理是很暴力的

引用来自“jockchou”的评论

可以分享一下你们的实现方式
已经分享过了,http://www.infoq.com/cn/articles/weibo-relation-service-with-redis/
jockchou
jockchou 博主

引用来自“终曲”的评论

很有想法,不过为了性能,我们实际的处理是很暴力的
可以分享一下你们的实现方式
终曲
终曲
很有想法,不过为了性能,我们实际的处理是很暴力的
gaodaojiang
gaodaojiang
haitaosoft
haitaosoft
以前写过一则:让redis也能实现数据库才有的増删改、查询过滤功能
http://blog.csdn.net/sz_haitao/article/details/18004459
jockchou
jockchou 博主

引用来自“FMN”的评论

NEO4J,图数据库
也是一个非常不错的方案。
jockchou
jockchou 博主

引用来自“芙蓉镇”的评论

数据量少的话还可以,处理海量数据时会有问题,比如百万粉丝,而且redis的交集指令在cluster环境下是不被支持的
数据量大,就把要查询那一页的分别都读出来判断关系。
微博关系服务与Redis的故事

新浪微博的工程师们曾经在多个公开场合都讲到过,微博平台当前在使用并维护着可能是世界上最大的Redis集群,其中最大的一个业务,单个业务使用了超过 10T 的内存,这里说的就是微博关系服务。...

greki
2014/04/30
260
0
微博关系服务与Redis的故事

2014-04-16 唐福林 InfoQ 新浪微博的工程师们曾经在多个公开场合都讲到过,微博平台当前在使用并维护着可能是世界上最大的Redis集群,其中最大的一个业务,单个业务使用了超过 10T 的内存,这...

Yamazaki
2014/04/23
1
0
日访问量百亿级的应用如何做缓存架构设计

数据挑战 Feed平台系统架构 总共分为五层,最上层是端层,比如web端,客户端,大家用的ios或安卓的一些客户端,还有一些开放平台,第三方接入的一些接口。下面是平台接入层,不同的池子,主要...

技术小能手
2018/05/07
0
0
百亿级日访问量的应用如何做缓存架构设计?

引言 “ 微博日活跃用户 1.6 亿+,每日访问量达百亿级,面对庞大用户群的海量访问,良好的架构且不断改进的缓存体系具有非常重要的支撑作用。 本文由新浪微博技术专家陈波老师,分为如下四个...

JK_OPERA
2018/08/01
46
0
微博应对日访问量百亿级的缓存架构设计

作者介绍 微博日活跃用户1.6亿+,每日访问量达百亿级,面对庞大用户群的海量访问,良好的架构且不断改进的缓存体系具有非常重要的支撑作用。本文将由新浪微博技术专家陈波老师,跟大家详细讲...

陈波
2018/06/05
0
0

没有更多内容

加载失败,请刷新页面

加载更多

mars-config 动态配置管理

mars-config 码云地址:https://gitee.com/fashionbrot/mars-config 介绍 spring mvc 、springboot 动态配置系统。http 轮训方式 更新 动态配置 软件架构 软件架构说明 后端使用技术 :sprin...

fashionbrot
19分钟前
9
0
女朋友玩吃鸡手游被开挂老哥骗炮,我见义勇为将骗子绳之以法

大家好,我是乔哥。 晚上10点以后下班后我回到自如出租房里面,开始处理公众号粉丝发来的消息,一条一条处理,突然看到了这么几条消息,吸引了我的眼球: 然后我就和这位女粉丝小红(化名)聊...

gzc426
25分钟前
3
0
两款软件

fadetop保护眼睛软件 Snipaste截图软件

伟大源于勇敢的开始
51分钟前
6
0
06.全局锁和表锁

根据加锁的范围,MySQL里面的锁大致可以分成全局锁、表级锁和行锁三类。 全局锁 全局锁就是对整个数据库实例加锁。MySQL提供了一个加全局读锁的方法,命令是flush tables with read lock(FTW...

scgaopan
今天
7
0
图解安装CentOS8

最近正式发布了CentOS8!迫不及待地准备下载了CentOS8镜像,准备体验下,工作繁忙无暇理会。 今天抽空安装体验下~ 可从CentOS官网下载:https://centos.org/download/ 为了快速可以选择从国...

技术训练营
昨天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部