我一直想知道Facebook如何设计朋友<->用户关系。
我认为用户表是这样的:
user_email PK
user_id PK
password
我用用户的数据(性别,年龄等假设通过用户电子邮件连接的表)来计算表格。
如何将所有朋友连接到该用户?
像这样吗
user_id
friend_id_1
friend_id_2
friend_id_3
friend_id_N
可能不是。因为用户数未知,并且会扩大。
我一直想知道Facebook如何设计朋友<->用户关系。
我认为用户表是这样的:
user_email PK
user_id PK
password
我用用户的数据(性别,年龄等假设通过用户电子邮件连接的表)来计算表格。
如何将所有朋友连接到该用户?
像这样吗
user_id
friend_id_1
friend_id_2
friend_id_3
friend_id_N
可能不是。因为用户数未知,并且会扩大。
Answers:
保留一个朋友表,该表包含用户ID,然后是朋友的UserID(我们将其称为FriendID)。两列都是返回到用户表的外键。
一些有用的示例:
Table Name: User
Columns:
UserID PK
EmailAddress
Password
Gender
DOB
Location
TableName: Friends
Columns:
UserID PK FK
FriendID PK FK
(This table features a composite primary key made up of the two foreign
keys, both pointing back to the user table. One ID will point to the
logged in user, the other ID will point to the individual friend
of that user)
用法示例:
Table User
--------------
UserID EmailAddress Password Gender DOB Location
------------------------------------------------------
1 bob@bob.com bobbie M 1/1/2009 New York City
2 jon@jon.com jonathan M 2/2/2008 Los Angeles
3 joe@joe.com joseph M 1/2/2007 Pittsburgh
Table Friends
---------------
UserID FriendID
----------------
1 2
1 3
2 3
这表明鲍勃是乔恩和乔的朋友,乔恩也是乔的朋友。在此示例中,我们将假定友谊始终是两种方式,因此您无需在表中显示诸如(2,1)或(3,2)之类的行,因为它们已经在另一个方向上表示了。例如,在友谊或其他关系不是明确的双向关系的示例中,您还需要使那些行指示双向关系。
看一下以下由Anatoly Lubarsky反向工程的数据库模式:
TL; DR:
他们对堆栈底部MySQL之上的所有内容都使用带有缓存图的堆栈体系结构。
长答案:
我本人对此进行了一些研究,因为我很好奇它们如何处理大量数据并快速进行搜索。我见过有人抱怨定制的社交网络脚本会随着用户群的增长而变慢。在我仅用1万个用户和250万个朋友连接进行了基准测试之后-甚至没有试图去烦恼群组权限,顶和墙贴-很快就证明了这种方法是有缺陷的。因此,我花了一些时间在网上搜索如何做得更好,并看到了这篇官方的Facebook文章:
我真的建议您在继续阅读之前观看上面第一个链接的演示。这可能是FB如何在您发现的幕后工作的最好解释。
视频和文章告诉您一些事情:
让我们看一下,朋友关系在左上方:
好吧,这是一张图。:)它没有告诉您如何使用SQL进行构建,它有多种实现方法,但是此站点有很多不同的方法。注意:请考虑关系数据库的本质:考虑存储标准化数据,而不是图形结构。因此它的性能不如专门的图形数据库好。
还要考虑到,您不仅要执行复杂的查询,而不仅仅是执行好友的查询,例如,当您要过滤给定坐标中您和您的好友的朋友喜欢的所有位置时。图表是此处的理想解决方案。
我无法告诉您如何构建它,使其性能良好,但显然需要进行反复试验和基准测试。
这是我失望的测试只是朋友的朋友的调查结果:
数据库架构:
CREATE TABLE IF NOT EXISTS `friends` (
`id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`friend_id` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
好友查询:
(
select friend_id
from friends
where user_id = 1
) union (
select distinct ff.friend_id
from
friends f
join friends ff on ff.user_id = f.friend_id
where f.user_id = 1
)
我真的建议您创建至少包含1万条用户记录的示例数据,并且每条记录至少具有250个朋友连接,然后运行此查询。在我的机器(i7 4770k,SSD,16gb RAM)上,该查询的结果约为0.18秒。也许可以对其进行优化,但我不是DB天才(欢迎提出建议)。但是,如果按比例缩放是线性的,那么对于100k用户而言,您已经达到1.8秒,对于100万用户而言已经为18秒。
对于大约10万名用户来说,这听起来还是不错的,但是请考虑您只是获取了朋友的朋友,并且没有执行任何更复杂的查询,例如“ 仅向我显示朋友的帖子,并进行权限检查(如果允许或不允许)查看其中一些+进行子查询以检查我是否喜欢其中任何一个。您想让数据库检查您是否喜欢某个帖子,否则必须在代码中进行。还要考虑这不是您运行的唯一查询,并且您在一个或多或少受欢迎的网站上同时拥有超过活动用户的查询。
我认为我的回答回答了Facebook如何很好地设计他们的朋友关系的问题,但是很抱歉,我无法告诉您如何以一种快速运行的方式来实现它。实施社交网络很容易,但是要确保其表现良好显然不是-IMHO。
我已经开始尝试使用OrientDB进行图形查询,并将边缘映射到基础SQL DB。如果我完成了,我会写一篇有关它的文章。
我最好的选择是他们创建了一个图形结构。节点是用户,“友谊”是边缘。
保留一张用户表,保留另一张边表。然后,您可以保留有关边缘的数据,例如“他们成为朋友的日子”和“批准的身份”等。
这很可能是多对多关系:
FriendList(表)
user_id -> users.user_id
friend_id -> users.user_id
friendVisibilityLevel
编辑
用户表可能没有user_email作为PK,但可能没有唯一键。
用户(表)
user_id PK
user_email
password
看看这些描述LinkedIn和Digg是如何构建的文章:
还有“大数据:Facebook数据团队的观点”可能会有所帮助:
另外,本文还讨论了非关系数据库以及某些公司如何使用它们:
http://www.readwriteweb.com/archives/is_the_relational_database_doomed.php
您会看到,这些公司正在处理数据仓库,分区数据库,数据缓存和其他更高层次的概念,这比我们大多数人每天都不曾处理过的要多。或者至少,也许我们不知道我们这样做。
前两篇文章中有很多链接,这些链接应该使您有更多的了解。
更新10/20/2014
Murat Demirbas撰写了关于
http://muratbuffalo.blogspot.com/2014/10/facebooks-software-architecture.html
高温超导
不可能从RDBMS检索用户朋友数据,而要获取恒定时间超过10亿的数据,因此Facebook使用哈希数据库(没有SQL)实现了这一点,他们开源了名为Cassandra的数据库。
因此,每个用户都有自己的密钥,并且朋友的详细信息在队列中。知道cassandra是如何工作的:
2013年6月的这篇最新文章详细介绍了从关系数据库到具有某些数据类型关联的对象的转换。
https://www.facebook.com/notes/facebook-engineering/tao-the-power-of-the-graph/10151525983993920
https://www.usenix.org/conference/atc13/tao-facebook's-distributed-data-store-social-graph上有更长的文章
您正在寻找外键。基本上,除非数据库具有自己的表,否则您无法在数据库中拥有数组。
用户表 用户ID PK 其他数据 朋友表 userID-用户表的FK,代表有朋友的用户。 friendID-FK到用户表,代表朋友的用户ID
它是一种图形数据库:http : //components.neo4j.org/neo4j-examples/1.2-SNAPSHOT/social-network.html
它与关系数据库无关。
Google用于图形数据库。
请记住,数据库表被设计为垂直增长(更多行),而不是水平增长(更多列)
关于多对多表的性能,如果您有2个32位int链接用户ID,则200,000,000个用户的平均数据存储量(平均每个200个朋友)不足300GB。
显然,您将需要进行一些分区和索引编制,并且不会为所有用户将其保留在内存中。
可能存在一个表,该表存储朋友<->用户关系,例如“ frnd_list”,具有字段“ user_id”,“ frnd_id”。
每当用户将另一个用户添加为朋友时,就会创建两个新行。
例如,假设我的ID为'deep9c',并且添加了一个ID为'akash3b'的用户作为我的朋友,则在表“ frnd_list”中创建了两个新行,其值分别为('deep9c','akash3b')和('akash3b ','deep9c')。
现在,当向特定用户显示好友列表时,一个简单的sql可以做到:“从frnd_list中选择frnd_id,其中user_id =”其中是已登录用户的ID(存储为会话属性)。