Search code examples
graphgremlinamazon-neptune

Best way to add two vertices and an edge atomically in Gremlin


I'm using Gremlin with AWS Neptune, and trying to add 2 vertices and 1 edge atomically. I've essentially used fold() + coalesce() semantics to traverse along the way such that I keep creating the elements if not already present. This is what I've come up with and was wondering if people have better alternatives to it.

         g.V("America")
                .fold()
                .coalesce(unfold(), addV("Country")
                                        .property(T.id, "America")
                                        .property("Population", 300_000_000))
          .V("India")
                .fold()
                .coalesce(unfold(), addV("Country")
                                        .property(T.id, "India")
                                        .property("Population", 1_000_000_000))
           .V("America")
                .outE("connected")
                .inV()
                    .has(T.id, "India")
                .fold()
                .coalesce(unfold(), addE("connected")
                                        .property("distanceMiles", 8000)
                                        .from(V("America"))
                                        .to(V("India"))).next();

Also, are there any tips to make queries more readable? I'm using JAVA, and since the steps need to be chained, parts of the query cannot be extracted out to it's own method so that it's re-usable. Is this understanding correct?

And a final question: IntelliJ gives me warnings about the query in the form of Unchecked generics array creation for varargs parameter which I am not being able to understand in this context. Can someone help clarify?

Thanks!


Solution

  • I could probably provide you other variations but the fold/coalesce/unfold is generally the way to do this so the code would end up looking roughly the same. Note that there are current discussions for major improvements to this pattern.

    Also, are there any tips to make queries more readable? I'm using JAVA, and since the steps need to be chained, parts of the query cannot be extracted out to it's own method so that it's re-usable. Is this understanding correct?

    Personally, I like the form you've taken, but there is nothing to say that chaining means you can't extract portions if you prefer that style. How about:

    private Traversal createCountryTraversal(String id, int pop) {
        return __.addV("Country").property(T.id, "America").property("Population", 300_000_000);
    }
    
    ...
    
        g.V("America")
                    .fold()
                    .coalesce(unfold(), createCountryTraversal("America", 300_000_000))
              .V("India")
                    .fold()
                    .coalesce(unfold(), createCountryTraversal("India",1_000_000_000))
               .V("America")
                    .outE("connected")
                    .inV()
                        .has(T.id, "India")
                    .fold()
                    .coalesce(unfold(), addE("connected")
                                            .property("distanceMiles", 8000)
                                            .from(V("America"))
                                            .to(V("India"))).next();
    

    You might also, pass the traversal object to different functions to do the chaining in them and then return back the traversal in a sort of meta-builder pattern. Or if you want something even more elegant, build a Gremlin DSL.

    And a final question: IntelliJ gives me warnings about the query in the form of Unchecked generics array creation for varargs parameter which I am not being able to understand in this context. Can someone help clarify?

    I assume it is an issue with coalesce() but some generics in Gremlin have a way of generating this warning in Java. I'm not sure that there is a way to avoid that warning.

    UPDATE: As of TinkerPop 3.6.0, the fold()/coalesce()/unfold() pattern has been largely replaced by the new steps of mergeV() and mergeE() which greatly simplify the Gremlin required to do an upsert-like operation.