Graph databases 基于边缘属性递归获取节点的Gremlin查询

Graph databases 基于边缘属性递归获取节点的Gremlin查询,graph-databases,gremlin,janusgraph,Graph Databases,Gremlin,Janusgraph,给定以下示例数据,我想构造一个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:

给定以下示例数据,我想构造一个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(Gremlin3)的最新版本。我对小精灵很陌生;我一直在思考一些与我想要的查询有共同点的食谱,但我仍然不知道如何达到目的


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

当您询问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]
更复杂的部分是在这之后,您关心的是检索每个路径的路径信息,以便您可以沿着每个“速率”边获取“值”属性。我选择使用
,这样我就可以很容易地得到您想要的
映射
结构。显然,如果“bobby”在树中出现两次,您将得到他的
Map
条目的两个评级列表

如果你把
group()
中发生的事情分开,你会发现它是由两个
by()
选项调制的。第一个对应于
映射中的键(显然,我假设“name”是唯一的)。第二个从当前遍历器(人顶点)中提取路径。在继续之前,先看看仅使用
path()
的输出是什么样子的:


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

当询问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]
更复杂的部分是在这之后,您关心的是检索每个路径的路径信息,以便您可以沿着每个“速率”边获取“值”属性。我选择使用
,这样我就可以很容易地得到您想要的
映射
结构。显然,如果“bobby”在树中出现两次,您将得到他的
Map
条目的两个评级列表

如果你把
group()
中发生的事情分开,你会发现它是由两个
by()
选项调制的。第一个对应于
映射中的键(显然,我假设“name”是唯一的)。第二个从当前遍历器(人顶点)中提取路径。在继续之前,先看看仅使用
path()
的输出是什么样子的:


path()
后面的步骤将该路径操作为所需的形式。它展开每条路径,然后通过查找“value”的“edge-only”属性过滤出边,然后提取该属性,然后将值折叠回地图中每个值的列表中。

谢谢Stephen!伟大的解决方案,以及伟大的解释+谢谢斯蒂芬!伟大的解决方案,以及伟大的解释+100