【问题标题】:Gremlin query to recursively fetch nodes based on edge propertiesGremlin 查询以基于边缘属性递归获取节点
【发布时间】:2017-07-16 04:57:19
【问题描述】:

鉴于以下示例数据,我想构建一个 Gremlin 查询,它返回 Alice 的 ruby​​ 连接网络,深度为 3 级:

Vertex: Alice
Vertex: Bobby
Vertex: Cindy
Vertex: David
Vertex: Eliza

Edge: [Alice] -> [Rates(tag:ruby,value:0.9)] -> [Bobby]
Edge: [Bobby] -> [Rates(tag:ruby,value:0.8)] -> [Cindy]
Edge: [Cindy] -> [Rates(tag:ruby,value:0.7)] -> [David]
Edge: [David] -> [Rates(tag:ruby,value:0.6)] -> [Eliza]   # ignored, level 4
Edge: [Alice] -> [Rates(tag:java,value:0.9)] -> [Eliza]   # ignored, not ruby

所以返回的数据应该是这样的:

Bobby: [0.9]
Cindy: [0.9, 0.8]
David: [0.9, 0.8, 0.7]

返回每个顶点 ID 以及评级值路径的数组。

我正在使用当前版本的 JanusGraph (Gremlin 3)。我对 Gremlin 很陌生;我一直在为一些与我想要的查询有共同之处的食谱感到困惑,但我仍然不知道如何到达那里......

非常感谢您提供的任何帮助或建议。

【问题讨论】:

    标签: graph-databases gremlin janusgraph


    【解决方案1】:

    在向 Gremlin 提问时,如果您提供一个可以像这样轻松剪切并粘贴到 Gremlin 控制台中的示例图表,对那些试图回答的人总是有帮助的:

    graph = TinkerGraph.open()
    g = graph.traversal()
    g.addV().property('name','alice').as('a').
      addV().property('name','bobby').as('b').
      addV().property('name','cindy').as('c').
      addV().property('name','david').as('d').
      addV().property('name','eliza').as('e').
      addE('rates').property('tag','ruby').property('value',0.9).from('a').to('b').
      addE('rates').property('tag','ruby').property('value',0.8).from('b').to('c').
      addE('rates').property('tag','ruby').property('value',0.7).from('c').to('d').
      addE('rates').property('tag','ruby').property('value',0.6).from('d').to('e').
      addE('rates').property('tag','java').property('value',0.9).from('a').to('e').iterate()
    

    使用此图表,我想出了这种方法来获得您想要的结果:

    gremlin> g.V().has('name','alice').
    ......1>   repeat(outE().has('tag','ruby').inV()).
    ......2>     times(3).
    ......3>     emit().
    ......4>   group().
    ......5>     by('name').
    ......6>     by(path().
    ......7>        unfold().
    ......8>        has('value').
    ......9>        values('value').
    .....10>        fold())
    ==>[bobby:[0.9],cindy:[0.9,0.8],david:[0.9,0.8,0.7]]
    

    使用emit() 跟进第 3 行可能是不言自明的 - 找到“alice”,然后反复遍历 out() 到 3 的深度,并发出沿途发现的每个顶点。这会让你得到你关心的顶点:

    gremlin> g.V().has('name','alice').
    ......1>   repeat(outE().has('tag','ruby').inV()).
    ......2>     times(3).
    ......3>     emit()
    ==>v[2]
    ==>v[4]
    ==>v[6]
    

    之后是更复杂的部分,您需要关注检索每个路径的路径信息,以便您可以沿每个“速率”边缘获取“值”属性。我选择使用group,以便我可以轻松获得您想要的Map 结构。显然,如果“bobby”在树中出现两次,您最终会得到两个针对他的Map 条目的评级列表。

    如果您将group() 中发生的事情分开,您可以看到它由两个by() 选项调制。第一个对应于Map 中的键(显然,我假设“名称”具有唯一性)。第二个从当前遍历器(人顶点)中提取路径。在继续之前,先看看 path() 的输出是什么样子的:

    gremlin> g.V().has('name','alice').
    ......1>   repeat(outE().has('tag','ruby').inV()).
    ......2>     times(3).
    ......3>     emit().
    ......4>   group().
    ......5>     by('name').
    ......6>     by(path()).next()
    ==>bobby=[v[0], e[10][0-rates->2], v[2]]
    ==>cindy=[v[0], e[10][0-rates->2], v[2], e[11][2-rates->4], v[4]]
    ==>david=[v[0], e[10][0-rates->2], v[2], e[11][2-rates->4], v[4], e[12][4-rates->6], v[6]]
    

    path() 之后的步骤将该路径操作为您想要的形式。它展开每条路径,然后通过查找“值”的仅边缘属性来过滤掉边缘,然后将其提取出来,然后将值折叠回地图中每个值的列表中。

    【讨论】:

    • 谢谢斯蒂芬!很好的解决方案,以及很好的解释。 +100。
    猜你喜欢
    • 1970-01-01
    • 2018-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多