我一直想知道 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
可能不是。因为用户数量是未知的,并且会扩大。
保留一个朋友表,其中包含用户 ID,然后是朋友的用户 ID(我们将其称为 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
这将表明 Bob 是 Jon 和 Joe 的朋友,并且 Jon 也是 Joe 的朋友。在这个例子中,我们将假设友谊总是有两种方式,所以你不需要在表中的一行,例如 (2,1) 或 (3,2),因为它们已经在另一个方向上表示了。对于友谊或其他关系不是明确的双向关系的示例,您还需要有这些行来指示双向关系。
他们使用带有缓存图的堆栈体系结构来存储堆栈底部 MySQL 之上的所有内容。
我自己对此进行了一些研究,因为我很好奇他们如何处理大量数据并快速搜索。我看到人们抱怨当用户群增长时定制的社交网络脚本变得很慢。在我用只有 10k用户和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
)
我真的建议您创建一些包含至少 10k 个用户记录并且每个记录至少有 250 个朋友连接的示例数据,然后运行此查询。在我的机器(i7 4770k、SSD、16gb RAM)上,该查询的结果约为 0.18 秒。也许可以优化,我不是数据库天才(欢迎提出建议)。但是,如果这是线性扩展,那么对于 10 万用户来说,你已经是 1.8 秒,对于 100 万用户来说是 18 秒。
对于大约 10 万用户来说,这可能听起来还不错,但考虑到您只是获取了朋友的朋友并且没有执行任何更复杂的查询,例如“只显示朋友朋友的帖子 + 进行权限检查是否允许或不允许看他们中的一些+做一个子查询来检查我是否喜欢他们中的任何一个“。您想让数据库检查您是否已经喜欢某个帖子,或者您必须在代码中进行。还要考虑这不是您运行的唯一查询,并且您在或多或少受欢迎的网站上同时拥有多个活跃用户。
我认为我的回答回答了 Facebook 如何很好地设计他们的朋友关系的问题,但很抱歉我不能告诉你如何以一种可以快速运行的方式实现它。实施社交网络很容易,但确保其表现良好显然不是 - 恕我直言。
我已经开始尝试使用 OrientDB 来进行图形查询并将我的边缘映射到底层 SQL DB。如果我完成它,我会写一篇关于它的文章。
2021 年 4 月 10 日更新:我可能永远不会写这篇文章;)但这里有一些要点,你可以如何尝试扩展它:
如果您以巧妙的方式结合上述列表中的要点,您可以构建一个性能非常好的系统。该列表不是“待办事项”列表,您仍然需要理解、思考和熟练使用它!https://microservices.io/是一个不错的网站,涵盖了我之前提到的一些主题。
我所做的是存储由聚合生成的事件,并使用项目和处理程序写入如上所述的不同数据库。很酷的一点是,我可以随时根据需要重新构建我的数据。
查看由 Anatoly Lubarsky 进行反向工程的以下数据库模式:
我最好的选择是他们创建了一个图形结构。节点是用户,“友谊”是边。
保留一张用户表,保留另一张边表。然后您可以保留有关边缘的数据,例如“他们成为朋友的日子”和“批准状态”等。
这很可能是多对多关系:
好友列表(表格)
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
您会看到这些公司正在处理数据仓库、分区数据库、数据缓存和其他更高级别的概念,而我们大多数人每天都不会处理这些概念。或者至少,也许我们不知道我们知道。
前两篇文章有很多链接,可以让您更深入地了解。
2014 年 10 月 20 日更新
Murat Demirbas写了一篇关于
http://muratbuffalo.blogspot.com/2014/10/facebooks-software-architecture.html
高温高压
不可能从 RDBMS 中检索用户朋友数据的数据,以获取在恒定时间内超过 50 亿的数据,因此 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 可以找到更长的论文
它是一种图形数据库: http ://components.neo4j.org/neo4j-examples/1.2-SNAPSHOT/social-network.html
它与关系数据库无关。
谷歌图数据库。
您正在寻找外键。基本上你不能在数据库中拥有一个数组,除非它有自己的表。
用户表 用户名 PK 其他数据 朋友桌 userID -- 代表有朋友的用户的用户表的 FK。 friendID -- FK 到代表朋友的用户 ID 的用户表
请记住,数据库表设计为垂直增长(更多行),而不是水平增长(更多列)
关于多对多表的性能,如果您有 2 个 32 位整数链接用户 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(存储为会话属性)。