Gremlin traversal using or(), repeat() filtering on edge labels and properties

1,429 views
Skip to first unread message

F Amer

unread,
Mar 31, 2020, 11:23:14 PM3/31/20
to Gremlin-users
I am trying come up with a traversal query that would give all vertices that are reachable from vertex 15 based on the criteria below.
Vertex 15  has a property 'innerId' set to a unique value 'node2'.
Criteria => I only want vertices that are reachable along edges that either have the label 'contains' OR have the label 'delivers' along with satisfying both these property filters - ignore != true & source = 'node2' 

I tried the following two ways but I get the error

gremlin> :> g.V('15').hasLabel('ROOT').repeat(or(__.outE('delivers').and(has('source','node2'),has('ignore',P.neq('true'))),__.outE('contains')).inV().simplePath()).emit().path()

{"requestId":"XXXXXXXXXXXXXXXX","code":"UnsupportedOperationException","detailedMessage":"EdgeVertexStep only applies to Edges."}


or

gremlin> :> g.V('15').hasLabel('ROOT').repeat(where(outE('delivers').and(has('source','node2'),has('ignore',P.neq('true'))).or().outE('contains')).inV().simplePath()).emit().path()

{"requestId":"XXXXXXXXXXXXXXXX","code":"UnsupportedOperationException","detailedMessage":"EdgeVertexStep only applies to Edges."}


I can traverse by using only edge labels but then I get extra vertices.
For example in the case below I am getting all vertices reachable from vertex 2 

gremlin> :> g.V('15').hasLabel('ROOT').repeat(__.outE('delivers','contains').inV().simplePath()).emit().path()

==>[v[15],e[17][15-delivers->2],v[2]]

==>[v[15],e[17][15-delivers->2],v[2],e[11][2-delivers->4],v[4]]

==>[v[15],e[17][15-delivers->2],v[2],e[12][2-delivers->3],v[3]]

==>[v[15],e[17][15-delivers->2],v[2],e[18][2-delivers->5],v[5]]

==>[v[15],e[17][15-delivers->2],v[2],e[12][2-delivers->3],v[3],e[13][3-contains->6],v[6]]

==>[v[15],e[17][15-delivers->2],v[2],e[18][2-delivers->5],v[5],e[19][5-contains->7],v[7]]

==>[v[15],e[17][15-delivers->2],v[2],e[12][2-delivers->3],v[3],e[13][3-contains->6],v[6],e[14][6-contains->8],v[8]]


The correct result should only give me  

==>[v[15],e[17][15-delivers->2],v[2]]

==>[v[15],e[17][15-delivers->2],v[2],e[18][2-delivers->5],v[5]]

==>[v[15],e[17][15-delivers->2],v[2],e[18][2-delivers->5],v[5],e[19][5-contains->7],v[7]]


The graph database is AWS Neptune.
The graph can be 4 - 5 levels deep.

This is the graph graph.

gremlin> :> g.addV('ROOT').property(T.id,'1').property('innerId','node1').next()
==>v[1]
gremlin> :> g.addV('N').property(T.id,'2').property('innerId','').next()
==>v[2]
gremlin> :> g.addV('N').property(T.id,'3').property('innerId','').next()
==>v[3]
gremlin> :> g.addV('N').property(T.id,'4').property('innerId','').next()
==>v[4]
gremlin> :> g.addV('N').property(T.id,'5').property('innerId','').next()
==>v[5]
gremlin> :> g.addV('N').property(T.id,'6').property('innerId','').next()
==>v[6]
gremlin> :> g.addV('N').property(T.id,'7').property('innerId','').next()
==>v[7]
gremlin> :> g.addV('N').property(T.id,'8').property('innerId','').next()
==>v[8]
gremlin> :> g.addV('ROOT').property(T.id,'15').property('innerId','node2').next()
==>v[15]
gremlin> :> g.addE('delivers').from(__.V('1')).to(__.V('1')).property(T.id, '9').property('ignore','true').property('source','node1').next()
==>e[9][1-delivers->1]
gremlin> :> g.addE('delivers').from(__.V('1')).to(__.V('2')).property(T.id, '10').property('ignore','').property('source','node1').next()
==>e[10][1-delivers->2]
gremlin> :> g.addE('delivers').from(__.V('2')).to(__.V('4')).property(T.id, '11').property('ignore','').property('source','node1').next()
==>e[11][2-delivers->4]
gremlin> :> g.addE('delivers').from(__.V('2')).to(__.V('3')).property(T.id, '12').property('ignore','').property('source','node1').next()
==>e[12][2-delivers->3]
gremlin> :> g.addE('contains').from(__.V('3')).to(__.V('6')).property(T.id, '13').property('ignore','').property('source','').next()
==>e[13][3-contains->6]
gremlin> :> g.addE('contains').from(__.V('6')).to(__.V('8')).property(T.id, '14').property('ignore','').property('source','').next()
==>e[14][6-contains->8]
gremlin> :> g.addE('delivers').from(__.V('15')).to(__.V('15')).property(T.id, '16').property('ignore','true').property('source','node2').next()
==>e[16][15-delivers->15]
gremlin> :> g.addE('delivers').from(__.V('15')).to(__.V('2')).property(T.id, '17').property('ignore','').property('source','node2').next()
==>e[17][15-delivers->2]
gremlin> :> g.addE('delivers').from(__.V('2')).to(__.V('5')).property(T.id, '18').property('ignore','').property('source','node2').next()
==>e[18][2-delivers->5]
gremlin> :> g.addE('contains').from(__.V('5')).to(__.V('7')).property(T.id, '19').property('ignore','').property('source','').next()
==>e[19][5-contains->7]


F Amer

unread,
Apr 1, 2020, 3:07:35 AM4/1/20
to Gremlin-users
I was able to use "coalesce" to do the traversal as below.

gremlin> :> g.V('15').hasLabel('ROOT').repeat(coalesce(outE('delivers').and(has('ignore',P.neq('true')),has('source','node2')),outE('contains')).inV().simplePath()).emit().path()

==>[v[15],e[17][15-delivers->2],v[2]]

==>[v[15],e[17][15-delivers->2],v[2],e[18][2-delivers->5],v[5]]

==>[v[15],e[17][15-delivers->2],v[2],e[18][2-delivers->5],v[5],e[19][5-contains->7],v[7]]


I have 2 additional questions:

1) Coalesce would only traverse along one of the 2 traversal options. Is there a way to traverse along both ?
2) How would I extract this traversal into a subgraph ?

Amiya

unread,
Apr 2, 2020, 1:32:14 PM4/2/20
to Gremlin-users

Try the below query it works.

g.V('15').hasLabel('ROOT').
repeat(__.outE('delivers', 'contains').
where(or(hasLabel('contains'),
and(has('source','node2'), has('ignore',P.neq('true'))))).
inV().simplePath()).
emit().path()

F Amer

unread,
Apr 3, 2020, 3:49:26 AM4/3/20
to Gremlin-users
Thanks it works.
I will play around a bit more with my full graph.

F Amer

unread,
Apr 18, 2020, 10:51:07 PM4/18/20
to Gremlin-users
After testing more with my full graph, I was able to remove the "and" and simplify the query  as below

g.V('15').hasLabel('ROOT').
repeat(__.outE('delivers', 'contains').
where(or(hasLabel('contains'),
has('source','node2'))).
inV().simplePath()).
emit().path()
However the or-Traversal can have one or more conditions and I have to do this in Java code.
For example in the query below I have 2 criteria for "has":

g.V('15').hasLabel('ROOT').
repeat(__.outE('delivers', 'contains').
where(or(hasLabel('contains'),
 has('source','node2'),
                                                 has('source','node3))).
inV().simplePath()).
emit().path()

My idea was to chain the or-conditions so I can use a loop on a list of the "has" conditions.

I tried to chain these or-conditions as below but it does not work and I get no results

g.V('15').hasLabel('ROOT').
repeat(__.outE('delivers', 'contains').
where(__.hasLabel('contains')
      .or(__.has('source','node2'))).
inV().simplePath()).
emit().path()

Any suggestions as to how I can create the comma-separated "has" conditions dynamically in Java code using a list and some kind of loop ? 

Amiya

unread,
Apr 19, 2020, 3:16:59 PM4/19/20
to Gremlin-users
What I understood, you want these number of conditions in or traversal dynamic.

Your code might look like below.
public Path getPath(...) {
   
return g.V(vertexId).
hasLabel('ROOT').
      repeat(outE('delivers', 'contains').
                        where(or(getOrTraversals(...))).
                     inV().simplePath()).
      emit().path();
}

private Traversal[] getOrTraversals(...) // Conditions can be passed as method arguments or refer to the object state
     
List<Traversal> orTraversals = new ArrayList<>();
     
     
if (some condition1) {
          
orTraversals.add(hasLabel('contains'));
      }

      if (some condition2) {
          
orTraversals.add(has('source','node2'));
      }

      if (some condition3) {
          
orTraversals.add(has('source','node3')));
      }

      return 
orTraversals.toArray(new Traversal[0]);
}

If you just want values of source to be dynamic only, then may be below

g.V('15').hasLabel('ROOT').
repeat(__.outE('delivers', 'contains').
where(or(hasLabel('contains'), 
                        has(source, within(getSources(...))))).
inV().simplePath()).
emit().path()

and then

private Collection<> 
getSources(...) {
    .....
}


F Amer

unread,
Apr 20, 2020, 1:02:16 AM4/20/20
to Gremlin-users
Thank you !
That is exactly what I was looking for.
Reply all
Reply to author
Forward
0 new messages