保存 Web 应用程序的动态图形结构
Save dynamic graph structure for a web application
我一直在寻找这个问题的答案,但是还没有找到令人满意的解决方案。
我正在尝试为 Web 应用程序存储动态无向图结构。它应该在彼此之间存储用户 "subscriptions",这可能会经常更改。
传统的数据库解决方案毫无意义。
JSON 每个用户的文件似乎也不是最佳解决方案,原因与数据库解决方案不理想的原因相同。
对于我的问题的最佳解决方案还有其他想法吗?
提前致谢!
您所谈论的结构类型在关系数据库中最有意义(这就是我假设您所说的 "traditional" 的意思)。因为你有用户之间的订阅,这是一种关系,因此,关系数据库最有意义。关系数据库允许不同 table 之间的显式连接。
文档数据库(即保存 JSON 文档的数据库)对于此类数据来说是一个非常糟糕的主意。文档数据库在某些方面可能非常擅长,但高度相互依赖的数据(如某种订阅系统)是文档数据库的不佳用途。我会在接下来的过程中进行更多解释。
你说你的图边是无向的,但你称它们为 "subscriptions" 的事实告诉我它们实际上是有向的:一个用户订阅另一个。如果它是无向的,它更像是在 facebook 上加好友或在 LinkedIn 上连接:如果我是你的朋友,那么你 必须 是我的朋友。在订阅系统中(比如 Google+ 或 Twitter),即使我订阅了你,你也不一定需要订阅我。如果我们都订阅对方,那么它实际上是两条有向边:一条是我给你的,一条是你给我的。
因此,最好的解决方案是至少有两个 table:一个主要的“users
”table和一个辅助的“subscriptions
”table。 “users
”table 将包含 uid
、name
、email
等列。 “subscriptions
”table 只有两列:subscriber
和 subscription
。两者都包含来自“users
”table 的 uid
值,并且每对值在 table.
中必须是唯一的
你问这是否会 "bloat up" 有这么多订阅。首先,您假设自己将成为下一个 Facebook,并且需要与数百万或数十亿用户打交道。别担心,你不会有这个问题,至少一开始是这样。其次,大多数关系数据库是 logarithmic in their performance for retrieving and inserting records, which scales very nicely as your numbers of users increases. For the type of behavior you are expecting from a document database or JSON files on disk, your behavior will either be of linear time complexity,因为您需要遍历 数据库中的每个 文档,以确保您已经检查了所有订阅(线性行为比例更差比对数),否则您将需要在所有记录中复制 subscriber/subscription 信息。第二种解决方案确实会变得臃肿,因为您正在复制大量数据,更重要的是,它 运行 很容易失去同步的巨大风险。在这种情况下,失去同步比您想象的要容易得多。
为了向您展示如何做到这一点,我将使用 sqlite3 dialect of SQL。这是我原型最多的,所以我最熟悉它。将其转换为 MySQL 或 PostgreSQL 之类的东西应该是相当简单的。以下是创建数据库的语句:
# since `uid` is the primary key, just pass it a
# null value on insertion and the database will
# generate a unique integer and use that automatically.
# it might also be good to make more than just the uid unique,
# such as their email.
CREATE TABLE users (uid INTEGER PRIMARY KEY,
name TEXT,
email TEXT);
# we will use the uid for the foreign key reference since this should
# never change, even if the user changes their name or email.
CREATE TABLE subrs (subscriber INTEGER,
subscription INTEGER,
# make sure each entry of pairs is unique
CONSTRAINT uc_edges UNIQUE (subscriber,subscription),
# be sure subscribers can only be created for users that exist
CONSTRAINT fk_subr FOREIGN KEY (subscriber) REFERENCES users(uid),
# be sure subscription can only be created for users that exist
CONSTRAINT fk_subee FOREIGN KEY (subscription) REFERENCES users(uid)
);
这通常有一个很好的额外好处,即您不能删除订阅了他们的用户,直到您先删除这些订阅。根据您选择的数据库,YMMV,因此请检查您选择的数据库的文档。几乎所有 SQL 数据库也支持使用外键的行为,即您不能使用尚不存在的外键值创建记录。使用 JSON 文件或文档数据库,很容易留下悬而未决的订阅或让用户删除花费很长时间,因为您需要修改引用给定用户的每个用户文档。关系型 SQL 数据库可以简化很多本来可以在您的代码中完成的事情。在您的应用程序代码中处理此逻辑会给您的数据处理带来更多错误和错误的机会。一点建议:您 可以 卸载到您的数据库中的工作,您 应该 卸载到您的数据库中。专业数据库比您的代码经过了更好的测试,并且已经具有您可能希望对数据执行的许多常见操作的逻辑。
要查找用户的订阅,您可以执行如下查询:
SELECT * FROM subrs WHERE subscriber=some_uid;
要获取给定用户的所有订阅者,查询同样简单:
SELECT * FROM subrs WHERE subscription=some_uid;
删除用户记录只需三行:
DELETE FROM subrs WHERE subscription=some_uid;
DELETE FROM subrs WHERE subscriber=some_uid;
DELETE FROM users WHERE uid=some_uid;
在文档数据库中,您将有更多的应用程序代码来执行非常相似的事情,并且您 运行 存在应用程序代码逻辑不佳和破坏数据的风险。
TL;DR
使用关系型 SQL 数据库。您可以在记录之间创建明确的关系。因此,不会像使用文档数据库那样容易搬起石头砸自己的脚(因为所有关系都只是隐含的)。 SQL 像 MySQL 这样的数据库也倾向于更好地扩展,无论是垂直(即具有更多用户记录)还是水平(即具有更多副本服务器)。
我一直在寻找这个问题的答案,但是还没有找到令人满意的解决方案。
我正在尝试为 Web 应用程序存储动态无向图结构。它应该在彼此之间存储用户 "subscriptions",这可能会经常更改。
传统的数据库解决方案毫无意义。 JSON 每个用户的文件似乎也不是最佳解决方案,原因与数据库解决方案不理想的原因相同。
对于我的问题的最佳解决方案还有其他想法吗?
提前致谢!
您所谈论的结构类型在关系数据库中最有意义(这就是我假设您所说的 "traditional" 的意思)。因为你有用户之间的订阅,这是一种关系,因此,关系数据库最有意义。关系数据库允许不同 table 之间的显式连接。
文档数据库(即保存 JSON 文档的数据库)对于此类数据来说是一个非常糟糕的主意。文档数据库在某些方面可能非常擅长,但高度相互依赖的数据(如某种订阅系统)是文档数据库的不佳用途。我会在接下来的过程中进行更多解释。
你说你的图边是无向的,但你称它们为 "subscriptions" 的事实告诉我它们实际上是有向的:一个用户订阅另一个。如果它是无向的,它更像是在 facebook 上加好友或在 LinkedIn 上连接:如果我是你的朋友,那么你 必须 是我的朋友。在订阅系统中(比如 Google+ 或 Twitter),即使我订阅了你,你也不一定需要订阅我。如果我们都订阅对方,那么它实际上是两条有向边:一条是我给你的,一条是你给我的。
因此,最好的解决方案是至少有两个 table:一个主要的“users
”table和一个辅助的“subscriptions
”table。 “users
”table 将包含 uid
、name
、email
等列。 “subscriptions
”table 只有两列:subscriber
和 subscription
。两者都包含来自“users
”table 的 uid
值,并且每对值在 table.
你问这是否会 "bloat up" 有这么多订阅。首先,您假设自己将成为下一个 Facebook,并且需要与数百万或数十亿用户打交道。别担心,你不会有这个问题,至少一开始是这样。其次,大多数关系数据库是 logarithmic in their performance for retrieving and inserting records, which scales very nicely as your numbers of users increases. For the type of behavior you are expecting from a document database or JSON files on disk, your behavior will either be of linear time complexity,因为您需要遍历 数据库中的每个 文档,以确保您已经检查了所有订阅(线性行为比例更差比对数),否则您将需要在所有记录中复制 subscriber/subscription 信息。第二种解决方案确实会变得臃肿,因为您正在复制大量数据,更重要的是,它 运行 很容易失去同步的巨大风险。在这种情况下,失去同步比您想象的要容易得多。
为了向您展示如何做到这一点,我将使用 sqlite3 dialect of SQL。这是我原型最多的,所以我最熟悉它。将其转换为 MySQL 或 PostgreSQL 之类的东西应该是相当简单的。以下是创建数据库的语句:
# since `uid` is the primary key, just pass it a
# null value on insertion and the database will
# generate a unique integer and use that automatically.
# it might also be good to make more than just the uid unique,
# such as their email.
CREATE TABLE users (uid INTEGER PRIMARY KEY,
name TEXT,
email TEXT);
# we will use the uid for the foreign key reference since this should
# never change, even if the user changes their name or email.
CREATE TABLE subrs (subscriber INTEGER,
subscription INTEGER,
# make sure each entry of pairs is unique
CONSTRAINT uc_edges UNIQUE (subscriber,subscription),
# be sure subscribers can only be created for users that exist
CONSTRAINT fk_subr FOREIGN KEY (subscriber) REFERENCES users(uid),
# be sure subscription can only be created for users that exist
CONSTRAINT fk_subee FOREIGN KEY (subscription) REFERENCES users(uid)
);
这通常有一个很好的额外好处,即您不能删除订阅了他们的用户,直到您先删除这些订阅。根据您选择的数据库,YMMV,因此请检查您选择的数据库的文档。几乎所有 SQL 数据库也支持使用外键的行为,即您不能使用尚不存在的外键值创建记录。使用 JSON 文件或文档数据库,很容易留下悬而未决的订阅或让用户删除花费很长时间,因为您需要修改引用给定用户的每个用户文档。关系型 SQL 数据库可以简化很多本来可以在您的代码中完成的事情。在您的应用程序代码中处理此逻辑会给您的数据处理带来更多错误和错误的机会。一点建议:您 可以 卸载到您的数据库中的工作,您 应该 卸载到您的数据库中。专业数据库比您的代码经过了更好的测试,并且已经具有您可能希望对数据执行的许多常见操作的逻辑。
要查找用户的订阅,您可以执行如下查询:
SELECT * FROM subrs WHERE subscriber=some_uid;
要获取给定用户的所有订阅者,查询同样简单:
SELECT * FROM subrs WHERE subscription=some_uid;
删除用户记录只需三行:
DELETE FROM subrs WHERE subscription=some_uid;
DELETE FROM subrs WHERE subscriber=some_uid;
DELETE FROM users WHERE uid=some_uid;
在文档数据库中,您将有更多的应用程序代码来执行非常相似的事情,并且您 运行 存在应用程序代码逻辑不佳和破坏数据的风险。
TL;DR
使用关系型 SQL 数据库。您可以在记录之间创建明确的关系。因此,不会像使用文档数据库那样容易搬起石头砸自己的脚(因为所有关系都只是隐含的)。 SQL 像 MySQL 这样的数据库也倾向于更好地扩展,无论是垂直(即具有更多用户记录)还是水平(即具有更多副本服务器)。