社交应用的多对多关系:Mongodb 或 Neo4j 等图形数据库
Posted
技术标签:
【中文标题】社交应用的多对多关系:Mongodb 或 Neo4j 等图形数据库【英文标题】:many-to-many relationships for social app: Mongodb or graph databases like Neo4j 【发布时间】:2012-02-14 20:56:51 【问题描述】:我试图了解在 Mongodb 中的嵌入,但找不到足够好的文档。不建议链接,因为写入在文档之间不是原子的,并且还有两个查找。有人知道如何解决这个问题吗?或者你会建议我去像 neo4j 这样的图形数据库。
我正在尝试构建一个需要多对多关系的应用程序。为了解释,我将以图书馆为例。它可以根据他的朋友正在阅读的书籍和邻居(志同道合)用户正在阅读的书籍向用户推荐书籍。
有用户和书籍。用户借书并有其他用户的朋友
-
给定一个用户,我需要他正在阅读的所有书籍以及相互阅读的数量
本书的朋友
给定一本书,我需要所有正在阅读它的人。可以给
用户A,这将返回人们阅读书籍的交集
和用户 A 的朋友。这是相互的友谊
用户 = [
name: 'xyz', 'id':'000000', friend_ids:['949583','958694'] name: 'abc', 'id':'000001', friend_ids:['949582','111111'] ]
书籍 = [
'book':'da vinci code', 'author': 'dan brown', 'readers'=['949583', '000000'] 'book':'iCon', 'author': 'Young', 'readers'=['000000', '000001'] ]
如上所示,如果我使用 mongo DB,通常我需要两个文档,因为我可能会采用两种方式查找。将文档复制(嵌入)到另一个文档中可能会导致大量重复(这些架构可能存储的信息比显示的多得多)。
我的数据建模是否正确?这可以在 mongodb 中有效地完成还是我应该查看图形数据库。
【问题讨论】:
【参考方案1】:免责声明:我为 Neo4j 工作
从您的大纲、要求和数据类型来看,您的应用似乎是图形数据库的最佳选择。
我建议您使用图形数据库进行快速峰值,看看它是如何进行的。
不会有重复 您有原子操作的事务 跟随链接是自然的操作 本地查询(例如来自用户或书籍)既便宜又快速 您可以使用最短路径等图形算法来查找有关数据的有趣信息 推荐和类似的操作对于图数据库来说是很自然的一些问题:
您当初为什么选择 MongoDB? 您使用什么实现语言?【讨论】:
感谢迈克尔的回复。我正在使用 python,由于熟悉和共享功能,我选择了 MOngoDB。我仍在分析像 neo4j 这样的图形数据库,并试图看看我是否可以获得类似的性能和共享能力。如果我的用例对于图形数据库来说太琐碎了,那么使用文档存储可能会更容易,你说呢? 听说neo4j读取性能不好,图数据库性能一般。为什么不直接使用 RDBMS?【参考方案2】:您上面的基本架构建议适用于 MongoDB,但有一些建议:
-
使用整数而不是字符串作为标识符。 MongoDB 通常会更紧凑地存储整数(它们将始终为 8 个字节,而字符串的存储大小将取决于字符串的长度)。您可以使用findAndModify 来模拟唯一的序列生成器(例如某些关系数据库中的 auto_increment)——请参阅Mongoengine's SequenceField 了解如何完成此操作的示例。您也可以使用ObjectIds,它始终为 12 个字节,但实际上可以保证是唯一的,而无需在数据库中存储任何协调信息。
您应该使用
_id
字段而不是 id
,因为该字段始终存在于 MongoDB 中,并且在其上创建了默认唯一索引。这意味着您的_id
s 始终是唯一的,_id
的查找速度非常快。
您是对的,使用这种模式将需要多个find()
s,并且每次都会产生网络往返开销。但是,对于您上面建议的每个查询,您需要不超过 2 次查找,并结合一些简单的应用程序代码:
-
“给定一个用户,我需要他正在阅读的所有书籍以及这本书的共同好友数量”
一个。查找有问题的用户,然后b。使用
db.books.find(_id: $in: [list, of, books, for, the, user])
查询图书收藏,然后c.对于每本书,计算该书的读者加上用户的朋友的集合并集
“给定一本书,我需要所有正在阅读它的人。”a.查找有问题的书,然后b。查找所有正在阅读该书的用户,再次使用$in
,例如db.users.find(_id: $in: [list, of, users, reading, book])
“可能给一个用户A,这将返回用户A的读书人与朋友的交集。”a.查找有问题的用户,然后b。查找有问题的书,然后c。计算用户朋友和图书读者的集合并集
我应该注意,如果您的列表很长,$in
可能会很慢,因为它实际上相当于对 N 个项目的列表进行 N 次查找。但是,服务器会为您执行此操作,因此它只需要一次网络往返而不是 N。
作为对其中一些查询使用$in
的替代方法,您可以在数组字段上创建索引,并在集合中查询具有数组中特定值的文档。例如,对于上面的查询 #1,您可以这样做:
// create an index on the array field "readers"
db.books.ensureIndex(readers: 1)
// now find all books for user whose id is 1234
db.books.find(readers: 1234)
这称为multi-key index,在某些情况下可以比$in
执行得更好。您的具体体验会因文档数量和列表大小而异。
【讨论】:
以上是关于社交应用的多对多关系:Mongodb 或 Neo4j 等图形数据库的主要内容,如果未能解决你的问题,请参考以下文章