Domanda

I have a Neo4j Cypher query. I am trying to understand how to do the same query in Tinkerpop/Gremlin (not Neo4j implementation).

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

Basically, I get two types of nodes (labels/types/whatever) and try to find where one points to another via property value match. I'll then create a real relationship using the results.

The graph is not very large, up to several thousand nodes.

È stato utile?

Soluzione

As with anything there are lots of ways to approach this. Since you have a small dataset, I didn't think it would be a problem to do lookups over g.V within the Gremlin pipeline. To simulate your problem, I created my own: Using the toy graph, add a sameFirstLetter edge to any vertex that had a lang property to any vertex that had an age property and where the first letter of their respective name properties was the same. In this case, it should add two vertices, from 5 to 4 and from 3 to 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]

There are two pieces to this code. The first constructs an adjacency list of matches and the second creates the edge. Here's the part that gets the adjacency list:

g.V.has('lang').transform{v->[v,g.V.has('age').filter{it.name.startsWith(v.lang[0])}.toList()]}

The above code basically says, grab all vertices that have a lang property (note that this use of has is part of the latest version of Gremlin - the soon to be released 2.4.0. Prior to 2.4.0 you could do .hasNot('lang',null) or something similar) and then convert them to a list where the first item in the list is the lang vertex and the second item in the list is a list of vertices in the graph that match on the first letter of name with the first letter of lang (in this case the letter j for both lang vertices).

.sideEffect{edgeList->edgeList[1].each{it.each{edgeList[0].addEdge('sameFirstLetter',it)}}}

The above sideEffect is processing this output...the adjacency list:

==>[v[3], [v[4]]]
==>[v[5], [v[4]]]

This operation could be performed as a separate line of code (not all Gremlin needs to be written in a single line...as satisfying as that may be). You could simply store the adjacency list to a variable then post-process it to create the edges. In any case, I chose to use sideEffect here, where I loop the list of lists creating edges as I go.

Alternatively, you could also make two passes through the dataset by building up an in-memory index keyed on the property value and then use that as a lookup to build the adjacency list. In this way you would only suffer two passes through the the vertex list:

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]]]

This gets you to the same adjacency list as found in the previous example. Edge creation via the adjacency list is still the performed as previously noted.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top