Search code examples
javagremlintinkerpop

Gremlin HasStep label condition on vertex or edge


Is there any way to find out if hasLabel() step is applied on vertices or edges? I know we can keep track of it while iterating through all the steps in recursion. But it may not be straight forward for the steps like SelectStep where we change the context. Is there any alternative way of doing it? For example: g.V().hasLabel("dataType1"), here we applied hasLabel() on the vertices.


Solution

  • At this time, there is no good way to determine the type of the current object being carried by the traverser. For determining a vertex from an edge in the stream, one common workaround is to try to use the presence of a particular property to determine the type. Assume you have this query which returns a mix of vertices and edges:

    gremlin> g.V().optional(outE())
    ==>e[9][1-created->3]
    ==>e[7][1-knows->2]
    ==>e[8][1-knows->4]
    ==>v[2]
    ==>v[3]
    ==>e[10][4-created->5]
    ==>e[11][4-created->3]
    ==>v[5]
    ==>e[12][6-created->3]
    

    In this graph the "weight" property can only be found on edges so therefore:

    gremlin> g.V().optional(outE()).
    ......1>   group().
    ......2>     by(choose(has('weight'),constant('edge'),constant('vertex'))).
    ......3>   unfold()
    ==>edge=[e[9][1-created->3], e[7][1-knows->2], e[8][1-knows->4], e[10][4-created->5], e[11][4-created->3], e[12][6-created->3]]
    ==>vertex=[v[2], v[3], v[5]]
    

    Here's another example using hasLabel() which was the subject of your question:

    gremlin> g.V().optional(outE()).
    ......1>   choose(has('weight'),
    ......2>          hasLabel('created'),
    ......3>          hasLabel('software'))
    ==>e[9][1-created->3]
    ==>v[3]
    ==>e[10][4-created->5]
    ==>e[11][4-created->3]
    ==>v[5]
    ==>e[12][6-created->3]
    

    The pattern in either case is to write an if/then statement using choose(), where the if-condition is simply a property that uniquely identify an element as a vertex or an edge.

    That said, I will say that I tend to avoid this problem all together when modelling and ensure that label values uniquely identify the vertex or edge. If you do that, you don't need to worry about this issue as you can then just do:

    gremlin> g.V().optional(outE()).
    ......1>   hasLabel('created','software')
    ==>e[9][1-created->3]
    ==>v[3]
    ==>e[10][4-created->5]
    ==>e[11][4-created->3]
    ==>v[5]
    ==>e[12][6-created->3]
    

    I would suggest taking that approach and simply preferring expressive verbs for the edges and noun representations for the vertices. If this modelling change is not possible or for some reason does not fit your use case then you will be forced to add a choose() step everywhere (or some similar approach). Of course, this situation would be a good opportunity to use a DSL to hide that complexity away and keep your Gremlin easy to read.