小猪的博客

朋友圈好友关系建模设计—好友关系设计

上周学院举办了一个建模比赛中:http://www.ippclub.org/index.php/archives/33/

最后成品放在了github上面:https://github.com/lizhuoli1126/FriendCircle

为了实现这个朋友圈的关系,确实有很多值得思考的地方。

第一个难点就在于这种朋友关系的设计。

第一种方案就是最简单直观的方法:一条记录对应一个朋友关系,user1和user2是好友,relation为friend。但是这样导致的问题就是会出现一条重复纪录,因为 ‘朋友’ 是一个双向关系,所以不应当user1,user2,friend和user2,user1,friend重复出现。

第二种方案就是在后端选择的时候加以判断,用 or 来选择两者之一。这样虽然后端的复杂程度增加了,但是其实只是一个选择判断语句,却换来了一半的IO请求,能大幅提高效率。查询的时候使用如下的SQL语句就可以了。

1
$userFriendList = $this->query("SELECT userID1,userID2 FROM relation WHERE (userID1 = '%s' OR userID2 = '%s') AND state = 'friend'",$userID, $userID);

随后,就是实现添加好友和删除好友。同样的,如果不加以选择,又回产生冗余纪录。添加好友肯定有一方是发送方,一方是接收方。如果不加以判断,会出现user1,user2,send和user2,user1,accept这种等价的两条记录,影响数据库读写效率,不可取。所以,正确的方法应该是在relation里面只有send,通过后端选择的时候进行判断,添加好友时候,如果user1和当前user相同,就是user1,user2,send,否则,就产生一个user2,user1,send。即如下:

1
2
3
4
5
6
7
if($checkFriendState[0]['userID1']==$userID1){
return true;
}
else{
$userFriendSet = $this->execute("UPDATE relation SET state = 'friend' WHERE userID1 = '%s' AND userID2 = '%s'",$userID1,$userID2);
return true;
}

第二个难点,也是二级需求里面的:3、屏蔽指定好友状态 4、禁止指定好友查看个人信息、朋友圈。

仔细分析,其实发现这个问题就是两种屏蔽状态的组合:屏蔽好友动态和屏蔽好友信息。

第一种方案:对屏蔽动态和屏蔽信息看成两个relation,都放在state字段中。这样的想法固然好,但是,如果继续要保证每两个用户之间只有一条记录,不仅state本身需要添加总共4×4(1对2屏蔽,2对1屏蔽,都不屏蔽,都屏蔽)个枚举值,后端的逻辑判断也非常复杂。这种方法虽然能想,但是不可取。

那么怎么办?行不可以咱们就改成列,第二种方案:增加两个新的字段:forbidMessage和forbidInfo,分别对应屏蔽动态和屏蔽信息,每个字段有四种状态(1to2,2to1,none,all)这样,在后端查询的时候多选择两列就可以简单判断出两个好友之间的屏蔽关系(对于数据库,多select出一列远比多扫描一倍字段要来的快)

查询大概就是这样的吧,比如查询是否屏蔽好友动态,可以这样,之后对forbidMessage进行判断就可以了。

1
$userFriendList = $this->query("SELECT userID1,userID2,forbidMessage FROM relation WHERE (userID1 = '%s' OR userID2 = '%s') AND state = 'friend' AND forbidMessage != 'none'",$userID, $userID);

有了这样的分析,数据库建立起来就很轻松了,relation表大概就是这样:

有兴趣的话,大家可以去我的github上看看最后的Demo(注意要看readme)~