Search code examples
gremlintinkerpopjanusgraphgremlin-server

traversal.asAdmin().addStep(step) for remote calls


I am trying to build complex traversals using Java client to a remote JanusGraph server.

The following traversal returns the ReferenceVertex elements identified by the label "mylabel":

GraphTraversal<Vertex, Vertex> t = g.V().hasLabel("mylabel");
List<Vertex> r = t.toList();

For more complex queries I need to concatenate multiple traversals that form a part of the whole queries. The following code illustrates the concept:

GraphTraversal<Vertex, Vertex> addMe = __.hasLabel("mylabel");
GraphTraversal<Vertex, Vertex> t = g.V();
for (Step<?, ?> step : addMe.asAdmin().getSteps()) {
     t.asAdmin().addStep(step);
}
List<Vertex> r = t.toList();

For local access this works. For remote access however, it returns all vertices available on the server, not the ones identified by the label.

In both cases, t.toString() returns

[GraphStep(vertex,[]), HasStep([~label.eq(mylabel)])]

What am I doing wrong?


Solution

  • I don't think you need to get into any of the asAdmin() methods. Rather than build anonymous traversals to try to append to a parent traversal, I think it would be better to just pass around the parent GraphTraversal instance and simply add steps to that as needed:

    private static GraphTraversal addFilters(GraphTraversal t) {
        return t.hasLabel("mylabel");
    }
    
    ...
    
    GraphTraversal<Vertex, Vertex> t = g.V();
    t = addFilters(t);
    List<Vertex> r = t.toList();
    

    There is a reason why your approach doesn't work with remote traversals and it has to do with how Gremlin bytecode is constructed behind the scenes. Using the asAdmin() methods bypasses some inner workings and those portions of the traversal are not sent to the server - that's a simple way of explaining it anyway. If you absolutely must construct anonymous portions of a traversal that way and then append them in that exact fashion then I guess I would do:

    GraphTraversal<Vertex, Vertex> addMe = __.hasLabel("mylabel");
    GraphTraversal<Vertex, Vertex> t = g.V();
    List<Vertex> r = t.filter(addMe).toList();
    

    I don't particularly like that approach because depending on what you're doing you could trick out JanusGraph traversal strategies that optimize your traversals and you'll lose some performance optimizations. I also don't like the style as much - it just seems more natural to pass around the GraphTraversal to the functions that need to mutate it with new steps. You might also find this information about traversal re-use helpful.