Search code examples
gremlinjanusgraphgremlin-server

Upsert query for JanusGraph which will issue an update to storage backend only if vertex properties are modified


I have the following Gremlin upsert query for a given vertex which does not issue an update to the JanusGraph storage backend if the property values for age or city has not changed.

Vertex marko = (Vertex) traversalSource.V()
        .has("person", "name", name)
        .fold()
        .coalesce(__.unfold(), __.addV("person").property("name", name))
        .choose(__.not(__.has("age", age)), __.property("age", age))
        .choose(__.not(__.has("city", city)), __.property("city", city))
        .next();

I tried to refactor this to make it more generic, with the property changes specified using a map.

Map<String, Object> propsToUpdate = new HashMap<>();
propsToUpdate.put("age", age);
propsToUpdate.put("city", city);
Vertex marko = (Vertex) traversalSource.withSideEffect("propsToUpdate", propsToUpdate)
        .V()
        .has("person", "name", name)
        .fold()
        .coalesce(__.unfold(), __.addV("person").property("name", name))
        .as("v")
        .select("propsToUpdate")
        .unfold()
        .as("updateProp")
        .select("v")
        .choose(__.not(__.has(__.select("updateProp").by(Column.keys).toString(),
                        __.select("updateProp").by(Column.values))),
                __.property(__.select("updateProp").by(Column.keys),
                        __.select("updateProp").by(Column.values)))
        .select("v")
        .next();

Unfortunately this generic query does issue an update to the storage backend even if none of the property values have changed.

Any clues as to why this difference in behavior between the 2 queries? Any suggestions to fix the generic query to make sure an update is not issued to the storage?

I am using JanusGraph 0.6.2 for these tests.


Solution

  • The condition inside __.has(__.select("updateProp").by(Column.keys).toString()) does not return the key of the updateProp, but rather returns the string representation of the bytecode of this anonymous traversal. This makes this condition always false (and its negation true) and the property is always updated.

    I do not believe gremlin allows to retrieve a vertex property using an as() variable, neither in the context of a has() step nor in a where() step.

    Possibly, your generalized query will be possible in JanusGraph-1.0 which will use TinkerPop 3.6.1. In this TinkerPop version it is possible to pass a Map to the property() step. This will make it easy to create a local temporary vertex inside the transaction from the propsToUpdate and compare it to the existing vertex. Only, in case of a difference you pass the Map to the property step for the existing vertex, drop the temporary vertex and commit the transaction.