与任何事情一样,有很多方法可以解决这个问题。由于您有一个小数据集,我认为g.V
在 Gremlin 管道中进行查找不会有问题。为了模拟您的问题,我创建了自己的问题:使用玩具图,将sameFirstLetter
边添加到具有lang
属性的任何顶点到具有age
属性并且它们各自name
属性的第一个字母相同的任何顶点。在这种情况下,它应该添加两个顶点,从 5 到 4 和从 3 到 4。
gremlin> g = TinkerGraphFactory.createTinkerGraph()
==>tinkergraph[vertices:6 edges:6]
gremlin> g.V.has('lang').transform{v->[v,g.V.has('age').filter{it.name.startsWith(v.lang[0])}.toList()]}.sideEffect{edgeList->edgeList[1].each{it.each{edgeList[0].addEdge('sameFirstLetter',it)}}}
==>[v[3], [v[4]]]
==>[v[5], [v[4]]]
gremlin> g.E
==>e[1][5-sameFirstLetter->4]
==>e[10][4-created->5]
==>e[0][3-sameFirstLetter->4]
==>e[7][1-knows->2]
==>e[9][1-created->3]
==>e[8][1-knows->4]
==>e[11][4-created->3]
==>e[12][6-created->3]
这段代码有两部分。第一个构造匹配的邻接列表,第二个创建边缘。这是获取邻接列表的部分:
g.V.has('lang').transform{v->[v,g.V.has('age').filter{it.name.startsWith(v.lang[0])}.toList()]}
上面的代码基本上是说,获取所有具有lang
属性的顶点(请注意,此使用has
是最新版本 Gremlin 的一部分 - 即将发布 2.4.0。在 2.4.0 之前,您可以执行.hasNot('lang',null)
或类似操作)和然后将它们转换为一个列表,其中列表中的第一项是lang
顶点,列表中的第二项是图中的第一个字母name
与第一个字母匹配的顶点列表lang
(在本例中j
为两个lang
顶点)。
.sideEffect{edgeList->edgeList[1].each{it.each{edgeList[0].addEdge('sameFirstLetter',it)}}}
上面的 sideEffect 正在处理这个输出......邻接列表:
==>[v[3], [v[4]]]
==>[v[5], [v[4]]]
此操作可以作为单独的代码行执行(并非所有 Gremlin 都需要编写在一行中……尽可能令人满意)。您可以简单地将邻接列表存储到一个变量中,然后对其进行后处理以创建边缘。在任何情况下,我都选择在sideEffect
这里使用,在这里我循环创建边的列表列表。
或者,您还可以通过建立一个以属性值为键的内存索引来对数据集进行两次遍历,然后将其用作查找来构建邻接列表。这样,您将只需要通过顶点列表两次:
gremlin> m=g.V.groupBy{it.name[0]}{it}.cap.next()
==>v=[v[2]]
==>r=[v[5]]
==>p=[v[6]]
==>l=[v[3]]
==>m=[v[1]]
==>j=[v[4]]
gremlin> g.V.has('lang').transform{[it,m[it.lang[0]]]}
==>[v[3], [v[4]]]
==>[v[5], [v[4]]]
这将使您进入与上一个示例中相同的邻接列表。通过邻接列表创建边缘仍然如前所述执行。