我有Neo4j
Cypher
个问题。我想了解如何在Tinkerpop
/ Gremlin
(不是Neo4j
实施)中执行相同的查询。
start
f=node:node_auto_index('_Element:field OR _Element:dynamicField'),
t=node:node_auto_index(_Element = 'fieldType')
where
f.type=t.name
return
f, t
基本上,我得到两种类型的节点(标签/类型/无论如何),并尝试通过属性值匹配找到一个指向另一个节点的位置。然后,我将使用结果创建一个真实的关系。
图表不是很大,最多可达数千个节点。
答案 0 :(得分:2)
与任何事情一样,有很多方法可以解决这个问题。由于您有一个小数据集,我认为在Gremlin管道中对g.V
进行查找并不是一个问题。为了模拟你的问题,我创建了自己的问题:使用toy graph,向任何具有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]
此代码有两部分。第一个构造匹配的adjacency list,第二个构建边缘。这是获得邻接列表的部分:
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]]]
这会使您进入与上一个示例中相同的邻接列表。通过邻接列表创建边缘仍然如前所述执行。