Search code examples
gremlingraph-databasestinkerpoptinkerpop3

Gremlin traverse path along the same property


I am trying to implement a gremlin query to for getting all vertex on same path based on property value. My graph looks like this. The label on graph is showing

  • name property and id for vertex
  • pathname property and id for edge

showing sample gremlin graph

Now the thing I want to achieve is when graph start from c and goes to e. I want to traverse with the starting edge property (any property would work in this case I have pathname property) and trace it's path up to e. To find path from c to e I am using.

g.V().has('name', 'c')
    .repeat(
        out()
    )
    .until(__.has('name', 'e'))
    .path()

But as you know this will give me two result for the path c->c1->c21->e (one with edge b1[c1] -> b1[c21] -> b1[e] another with edge from b1[c1] -> pb1[c21] -> b1[e]) But I want to get only one path as b1 is the only edge that start from c and goes all the way to e.

So the expected output for all the path query would be these path and total count would be 4.

//edge propertyname => path[vertex] -> path[vertex]
b1 => b1[c1] -> b1[c21] -> b1[e]
a1 => a1[d] -> a1[e]
d1 => d1[c3] -> d1[e]
c1 => c1[c2] -> c1[c31] -> c1[e]

Sample graph url https://gremlify.com/wij8933eelj

EDIT: there is a similar question here which is similar in nature but it doesnot resolve it in my case Gremlin simple path query, to get path based on first edge encountered property

Now for the case in which that does not work

Let's add an broken edge
c->d (pathname: r1) 
c21->e (pathname: r1)
Now the path returned for c->c1->c21->e becomes
b1->b1->b1 //within expectation
b1->b1->r1 //breaks here we only want edge with same pathname

Solution

  • I took the graph from Gremlify and pretty printed it. So we start with:

    g.addV('vertex').as('1').property(single, 'name', 'a').
      addV('vertex').as('2').property(single, 'name', 'b').
      addV('vertex').as('3').property(single, 'name', 'c').
      addV('vertex').as('4').property(single, 'name', 'd').
      addV('vertex').as('5').property(single, 'name', 'e').
      addV('vertex').as('6').property(single, 'name', 'f').
      addV('vertex').as('7').property(single, 'name', 'c1').
      addV('vertex').as('8').property(single, 'name', 'c2').
      addV('vertex').as('9').property(single, 'name', 'c3').
      addV('vertex').as('10').property(single, 'name', 'c21').
      addV('vertex').as('11').property(single, 'name', 'c31').
      addE('edge').from('1').to('2').property('pathname', 'a1').
      addE('edge').from('2').to('3').property('pathname', 'a1').
      addE('edge').from('3').to('7').property('pathname', 'b1').
      addE('edge').from('3').to('8').property('pathname', 'c1').
      addE('edge').from('3').to('9').property('pathname', 'd1').
      addE('edge').from('3').to('4').property('pathname', 'a1').
      addE('edge').from('3').to('4').property('pathname', 'pa2').
      addE('edge').from('4').to('5').property('pathname', 'a1').
      addE('edge').from('5').to('6').property('pathname', 'a1').
      addE('edge').from('7').to('10').property('pathname', 'b1').
      addE('edge').from('7').to('10').property('pathname', 'pb1').
      addE('edge').from('8').to('11').property('pathname', 'c1').
      addE('edge').from('8').to('11').property('pathname', 'pc1').
      addE('edge').from('9').to('5').property('pathname', 'd1').
      addE('edge').from('10').to('5').property('pathname', 'b1').
      addE('edge').from('11').to('5').property('pathname', 'c1')  
    

    I then added the extra edges you mentioned in the comments using:

    g.V().has('name','c').as('c').
      V().has('name','d').as('d').
      V().has('name','c21').as('c21').
      V().has('name','e').as('e').
      addE('edge').from('c').to('d').property('pathname','r1').
      addE('edge').from('c21').to('e').property('pathname','r1')
    

    This gives us the following graph (rendered using graph-notebook):

    example graph

    The following query will only follow paths using properties found on the initial edges starting from c

    g.V().has('name','c').as('v1').
      outE().values('pathname').as('n').
      select('v1').as('start').
      repeat(
        outE().where(eq('n')).by('pathname').by().inV()).
      until(has('name','e')).
      path().from('start').
        by('name').
        by('pathname')
    

    and we only get back paths where each edge has the same pathname

    1   path[c, a1, d, a1, e]
    2   path[c, b1, c1, b1, c21, b1, e]
    3   path[c, c1, c2, c1, c31, c1, e]
    4   path[c, d1, c3, d1, e]