【问题标题】:Neo4j or MongoDB for relative attributes/relationsNeo4j 或 MongoDB 用于相关属性/关系
【发布时间】:2018-04-06 14:40:20
【问题描述】:

我希望建立一个对象数据库,这些对象之间具有各种类型的关系。我举个例子会更容易解释。

我希望有一组对象,每个对象都由一个唯一的名称和一组属性(例如,身高、体重、颜色等)描述,但这些属性可能包含的值不是值,而是 相对于其他对象。例如,我可能有两个对象 A 和 B,其中 A 的高度为 1,重量为“B + 2 的重量”,B 的高度为“A + 3 的高度”和重量 4。

有些对象可能具有完全不同的属性;例如,对象 C 可能表示一个盒子,对象 A 和 B 将通过“我在 C 中出现 x 次”的关系与 C 相关。

查询可能包括“A/B 的高度是多少”或 C 中出现的具有多重性的对象的总重量是多少。

我对 MongoDB 有点熟悉,喜欢它的简单性。我听说过 Neo4j,但从未尝试过使用它。从它的描述来看,它听起来更适合我的需要(但我不能说它能够胜任这项任务)。但是,简单的 MongoDB 也适用吗?或者可能是不同的数据库引擎?

我不确定这是否重要,但我计划使用 python 作为处理查询及其输出的引擎。

【问题讨论】:

    标签: database mongodb neo4j graph-databases


    【解决方案1】:

    这两个都可以。我更喜欢 neo4j,但无论哪种方式都可以。

    在 neo4j 中,您将创建一个由节点 (A) 及其“基” (B) 组成的图。然后你可以像这样连接它们:

    (A:Node { weight: "base+2" })-[:base]->(B:Node { weight: 2 })

    请注意,以这种方式建模可以将基础关系更改为指向另一个节点,而无需更改任何关于 A 的内容。缺点是您需要一个迷你计算器来扩展诸如“base+2”之类的表达式,这很容易,但无论如何都是额外的工作。

    以另一种方式解释您的问题,您可能需要一个触发器。 Here's an article on neo4j triggers, how graphs handle this。如果在读取时解析该表达式“base+2”不是您想要的,并且您希望将 A 上的值实际设置为 b.weight + 2,那么您需要一个触发器。这将允许您定义在图形以某种方式更新时要运行的其他函数。在这种情况下,当有人在图表中插入新的:base 关系时,您可能会检查基值(关系的端点)并将其权重加 2,然后在关系的源上设置该新属性值。

    【讨论】:

    • 我不知道 Neo4j 触发器支持。听起来很方便!
    • 好吧,说实话,neo4j 还不支持触发器,但是 Max 的博客真的很棒,他可以向您展示如何使用已经存在一段时间的现有服务器扩展来实现它。由你来定义你想要什么样的触发器的范围。但是您的用例:“根据其他一些数据计算 X”是 经典的数据库触发器用例。
    【解决方案2】:

    是的,您可以使用任一 DBMS。

    为了帮助您做出决定,这是一个如何在 neo4j 中支持您的用例的示例。

    创建示例数据:

    CREATE
        (a:Foo {id: 'A'}), (b:Foo {id: 'B'}), (c:Box {id: 123}),
        (h1:Height {value: 1}), (w4:Weight {value: 4}),
        (a)-[:HAS_HEIGHT {factor: 1, offset: 0}]->(h1),
        (a)-[:HAS_WEIGHT {factor: 1, offset: 2}]->(w4),
        (b)-[:HAS_WEIGHT {factor: 1, offset: 0}]->(w4),
        (b)-[:HAS_HEIGHT {factor: 1, offset: 3}]->(h1),
        (c)-[:CONTAINS {count: 5}]->(a),
        (c)-[:CONTAINS {count: 2}]->(b);
    

    “A”和“B”由Foo 节点表示,“C”由Box 节点表示。由于给定的身高或体重可以被多个节点引用,因此此示例数据模型使用共享的WeightHeight 节点。 HAS_HEIGHTHAS_WEIGHT 关系具有 factoroffset 属性,以允许调整特定 Foo 节点的高度或重量。

    查询“A的高度是多少”:

    MATCH (:Foo {id: 'A'})-[ra:HAS_HEIGHT]->(ha:Height)
    RETURN ra.factor * ha.value + ra.offset AS height;
    

    查询“A和B的高度比是多少”:

    MATCH
      (:Foo {id: 'A'})-[ra:HAS_HEIGHT]->(ha:Height),
      (:Foo {id: 'B'})-[rb:HAS_HEIGHT]->(hb:Height)
    RETURN
      TOFLOAT(ra.factor * ha.value + ra.offset) /
      (rb.factor * hb.value + rb.offset) AS ratio;
    

    注意:上面使用了TOFLOAT(),以确保从不使用会截断的整数除法。

    查询“C中出现的对象的总重量是多少”:

    MATCH (:Box {id: 123})-[c:CONTAINS]->()-[rx:HAS_WEIGHT]->(wx:Weight)
    RETURN SUM(c.count * (rx.factor * wx.value + rx.offset));
    

    【讨论】:

    • 感谢您提供详细示例!我需要学习一点。
    【解决方案3】:

    我没用过Mongo,研究了一下决定不用。因此,请记住这一点来过滤我的意见;用户可能会发现我的 cmets 很容易克服。 Mongo 不是真正的图形数据库。用户必须创建和管理关系。在 Neo4j 中,关系是“原生的”并且是健壮的。

    在这个网站上有一个正面对比: [https://db-engines.com/en/system/MongoDB%3bNeo4j]

    另见:https://stackoverflow.com/questions/10688745/database-for-efficient-large-scale-graph-traversal

    NoSQL(例如 Mongo)和真正的图形数据库之间存在区别。许多人似乎认为,如果它不是 SQL,那么它就是一个图形数据库。这不是真的。大多数 NoSQL 数据库不存储关系。免费的book 在第 2 章中对此进行了描述。

    就我个人而言,我是在 Neo4j 上出售的。它使关系、传输图表和沿路径收集列表变得简单而强大。

    【讨论】:

    • 可能是比较链接坏了?
    猜你喜欢
    • 1970-01-01
    • 2015-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-14
    相关资源
    最近更新 更多