【问题标题】:How to structure a graph database to support 3-way relationships?如何构建图形数据库以支持三向关系?
【发布时间】:2014-01-15 14:52:20
【问题描述】:

我一直在尝试为我一直在开发的个人 web 应用程序找出数据库后端。由于我在数据中需要的灵活性,关系数据库是不可行的,并且可能需要某种形式的文档存储。当我了解图数据库时,我觉得这将是完美的。

但是,我遇到了一个问题:我需要能够以某种方式定义三向关系。我还没有决定数据库,但我一直在修补 Neo4j,所以我将使用 Cypher 来描述问题。

基本上,我从这个开始:

(a:N)-[r:E]->(b:N)

我需要的是一种将多个节点与 a 和 b 以及 r 相关联的方法。这些其他节点将存储关于所有 3 的不同信息。我决定可能只有两种方法来处理这个问题:将关系存储在自己的节点中或存储对包含信息的节点的引用并创建伪边.我认为前者可能是一个更好的主意,可以为我们提供更像这样的东西:

(a:N)<-[:E]-(r:R)->[:E](b:N)
(s:S)->(a)
(s)->(r)
(s)->(b)

所以,现在,这导致了查询数据的问题。使用图形数据库的重点在于能够遍历图形。如果我做这样的事情,有没有办法在 N 类型的节点之间递归遍历?处理这个的正确方法是什么?我已经想到了几种不同的方法来处理这个问题,但它们都有自己的缺点。是否有特定的图形数据库原生支持此类功能?

更新

使用原始代码,我能够使用以下代码递归遍历节点:

MATCH (a:N)-[:E*]->(b:N)
RETURN a,b

但是,一旦我将边拉到超边中,我无法确定是否有一种方法能够递归地遍历图形到未确定的深度,因为我将交替使用节点类型。我正在寻找类似的东西

MATCH chain=((a:N)-[]->(r:R)-[]->(b:N))*
RETURN [nodes of type N along the chain]

如果答案只是在创建超边的同时在 a 和 b 之间创建一条边,那么我的问题就变成了:有没有一种好的方法可以确保将边和超边一起移除?基本上,两者都感觉像是一种变通方法,而不是实际的解决方案。

【问题讨论】:

    标签: neo4j graph-databases orientdb titan


    【解决方案1】:

    您描述的场景由提到的超边模式@Pangea 在属性图模型中处理。您基本上将边缘(需要边缘进出它)转换为顶点。对于图表,我认为它不是一种非规范化,而是一种不同的建模抽象。

    就对边上的边的原生支持而言,您标记问题的图表都没有直接支持这样的功能。由于您确实包含了 Titan 和 OrientDB,我假设您也在评估 TinkerPop 作为您解决方案的可能部分,我可以进一步说,由于蓝图不支持边上的边,所以蓝图图也不支持。

    就遍历而言,我不能说我完全遵循“递归遍历”的意思。如果您能详细说明一下,我可以尝试修改我的答案。我将添加这个简单的示例,说明如何从“a”顶点遍历以查找 Gremlin 中的所有其他相关顶点(抱歉,我不知道 Cypher):

    gremlin> g = new TinkerGraph()
    ==>tinkergraph[vertices:0 edges:0]
    gremlin> va = g.addVertex([type:'N',name:'a'])
    ==>v[0]
    gremlin> er = g.addVertex([type:'R',name:'r'])
    ==>v[1]
    gremlin> vb = g.addVertex([type:'N',name:'b'])
    ==>v[2]
    gremlin> vc = g.addVertex([type:'N',name:'c'])
    ==>v[5]
    gremlin> va.addEdge('e',er)
    ==>e[3][0-e->1]
    gremlin> vb.addEdge('e',er)
    ==>e[4][2-e->1]
    gremlin> vc.addEdge('e',er)                   
    ==>e[6][5-e->1]
    gremlin> va.out.in.except([va]).name
    ==>c
    ==>b
    gremlin> vd = g.addVertex([type:'N',name:'d'])
    ==>v[7]
    gremlin> es = g.addVertex([type:'R',name:'s'])
    ==>v[8]
    gremlin> vb.addEdge('e',es)
    ==>e[9][2-e->8]
    gremlin> vd.addEdge('e',es)
    ==>e[10][7-e->8]
    gremlin> x=[];va.aggregate(x).out.in.except(x).loop(4){it.loops<2}.name
    ==>c
    ==>b
    gremlin> x=[];va.aggregate(x).out.in.except(x).loop(4){it.loops<3}.name
    ==>d
    

    关于:

    如果答案只是在 a 和 b 之间创建一条边,而 创建超边缘,那么我的问题就变成了:有没有好的方法 保证边和超边一起去掉?

    当您移除“超边”顶点时,您将自动移除与其相连的边,因此您可以有效地将它们一起移除。

    【讨论】:

    • 我已经更新了 OP,提供了更多关于我正在寻找的信息。我列出了这三个,因为它们是我脑海中浮现的那些。我真的在寻找能够解决我所有问题的任何类型的数据库,而图形数据库是最接近的。我只是还没有找到完美的。
    • 稍微更新了我的答案。回应如何在给定此模型的情况下删除“超边”并扩展我的代码以包含一些“深度”,您可以循环遍历以遍历任意深度(再次,抱歉......我不知道密码)。图形在建模时提供了一些非常丰富的抽象......虽然将顶点用于您认为是边的东西可能感觉不自然,但可能并非如此。图表是关于事物和事物之间的关系...有时可以将“关系”本身视为“事物”并将其建模为“事物”,如果您的领域需要它,那很好。
    • 我的问题是:如果我有 (a:N)[:E](b:N) 那么我必须创建 ( a)-[e:E]->(b) 为了递归地遍历我的 N 类型节点,即去 a->b->c->d 或者有没有办法做到之间的超边缘每个节点?因为它现在看起来像 a->r1->b->r2->c->r3->d。如果我创建超边,我正在寻找一种不必创建辅助边的方法,即某种方式将 a 和 b 之间的新关系定义为通过 r,这样我就可以说做 X 次.
    • 您不需要创建辅助(a)-[e:E]-&gt;(b) 以至少使用 Gremlin 进行递归遍历。我在示例中创建的图表显示:a->rsr1->b->r2->c->r3-> d"(边缘的方向性和少一级的深度)。该示例显示了使用 loop 递归到深度 1 和 2(即最后两行中的 it.loops&lt;2it.loops&lt;3)
    • 进一步考虑这一点,如果你可以保持边缘的方向性使得所有边缘都指向“外”,那么你不会有比我所展示的更简单的递归遍历,因为你不会必须聚合/排除遍历中的步骤。
    【解决方案2】:

    是否有特定的图形数据库本身支持这种类型的功能?

    确实有! Grakn 支持原生超边,在其语法中称为relation。匹配关系及其相关元素的最简洁方式如下所示:

    match ($a, $b, $r) isa E; get;
    

    全面披露:我在 Grakn 工作 ;)

    【讨论】:

      【解决方案3】:

      查看 Neo4j 文档中的 Hyperedges 模式。

      【讨论】:

      • 你能详细说明一下吗?我之前看到过,但它似乎并没有解决我的递归问题。我能收集到的最好的结果是,也许我应该在 a 和 b 之间创建一条边,同时还创建允许两全其美的关系节点。然而,这将被称为关系数据库中的非规范化,这通常是不受欢迎的,但似乎在这里作为一个特性被炫耀,所以我不确定我是否完全明白这个想法。
      • 链接已失效。您能否提供更多关于这意味着什么的信息?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多