Gremlin 查询以根据边属性递归获取节点
Gremlin query to recursively fetch nodes based on edge properties
给定以下示例数据,我想构建一个 Gremlin 查询,其中 returns 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 很陌生;我一直对一些与我想要的查询有共同点的食谱感到困惑,但我仍然不太明白如何到达那里......
非常感谢您提供的任何帮助或建议。
在询问 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]]
通过第 3 行跟进 emit()
可能是不言自明的 - 找到 "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]
更复杂的部分出现在这之后,您关心的是检索每个路径信息,以便您可以沿每个 "rates" 边获取 "value" 属性。我选择使用 group
这样我就可以很容易地得到你想要的 Map
结构。显然,如果 "bobby" 在树中出现两次,您最终会得到他的 Map
条目的两个评级列表。
如果你把 group()
中发生的事情分开,你会发现它是由两个 by()
选项调制的。第一个对应于 Map
中的键(显然,我假设在 "name" 上是唯一的)。第二个从当前遍历器(人顶点)中提取路径。在继续之前,先看看 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()
之后的步骤将该路径操作成您想要的形式。它展开每条路径,然后通过仅查找 "value" 的边缘 属性 来过滤掉边缘,然后提取它,然后将值折叠回地图中每个值的列表。
给定以下示例数据,我想构建一个 Gremlin 查询,其中 returns 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 很陌生;我一直对一些与我想要的查询有共同点的食谱感到困惑,但我仍然不太明白如何到达那里......
非常感谢您提供的任何帮助或建议。
在询问 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]]
通过第 3 行跟进 emit()
可能是不言自明的 - 找到 "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]
更复杂的部分出现在这之后,您关心的是检索每个路径信息,以便您可以沿每个 "rates" 边获取 "value" 属性。我选择使用 group
这样我就可以很容易地得到你想要的 Map
结构。显然,如果 "bobby" 在树中出现两次,您最终会得到他的 Map
条目的两个评级列表。
如果你把 group()
中发生的事情分开,你会发现它是由两个 by()
选项调制的。第一个对应于 Map
中的键(显然,我假设在 "name" 上是唯一的)。第二个从当前遍历器(人顶点)中提取路径。在继续之前,先看看 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()
之后的步骤将该路径操作成您想要的形式。它展开每条路径,然后通过仅查找 "value" 的边缘 属性 来过滤掉边缘,然后提取它,然后将值折叠回地图中每个值的列表。