Search code examples
gremlintinkerpoptinkerpop3

The provided traversal does not map to a value


I am trying to execute a math query.

gts.V()
.hasLabel("account")
.has("id",42)
.both("account_label1").as("label1")
.and(__.identity()
        .project("a","b")
        .by(__.identity()
                .both("label1_label2")
                .both("label2_label3")
                .values("createTime"))
        .by(__.identity()
                .both("label1_label4")
                .both("label4_label5")
                .values("launchTime"))
        .math("floor((a-b)/(86400))").is(100))
.select("label1")
.toList()

Above query fails with error

The provided traverser does not map to a value: v[137]->[IdentityStep, VertexStep(BOTH,[label1_label2],vertex), VertexStep(BOTH,[label2_label3],vertex), NoOpBarrierStep(2500), PropertiesStep([createTime],value)]
  1. Why is gremlin injection NoOpBarrierStep?
  2. What is the meaning of the NoOpBarrierStep(2500)?
  3. What will be the correct gremlin query for the same?

Solution

  • When you use project() it expects a value for each by() modulator and that value should not produce an empty Iterator. Here's a simple example:

    gremlin> g = TinkerFactory.createModern().traversal()
    ==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
    gremlin> g.V().project('x').by(out())
    ==>[x:v[3]]
    The provided traverser does not map to a value: v[2]->[VertexStep(OUT,vertex)]
    Type ':help' or ':h' for help.
    Display stack trace? [yN]
    

    The first vertex is able to traverse out() but the next one processed by project() has no outgoing edges and therefore produces this error. In your case, that simply means that not all of your traversers can traverse both().both() or if they can, you would want to be sure that they all had "createTime" property values. Either of those scenarios could cause the problem.

    You could fix this in a variety of ways. Obviously, if it's a data problem you could simply fix your data and always assume that the traversal path is right. If that's not the case, you need to write your Gremlin to be a bit more forgiving if the traversal path is not available. In my case I could do:

    gremlin> g.V().project('x').by(out().fold())
    ==>[x:[v[3],v[2],v[4]]]
    ==>[x:[]]
    ==>[x:[]]
    ==>[x:[v[5],v[3]]]
    ==>[x:[]]
    ==>[x:[v[3]]]
    

    Perhaps in your case you might do:

    by(coalesce(both("label1_label2").both("label2_label3").values("createTime"),
                constant('n/a')))
    

    Note that you do not need to specify identity() for the start of your anonymous traversals.

    Finally, in answer to your questions about NoOpBarrierStep, that step is injected into traversals where Gremlin thinks it can take advantage of a bulking optimization. You can add them yourself with barrier() step as well. Here's a quick description of "bulking" as taken from the TinkerPop Reference Documentation:

    The theory behind a "bulking optimization" is simple. If there are one million traversers at vertex 1, then there is no need to calculate one million both()-computations. Instead, represent those one million traversers as a single traverser with a Traverser.bulk() equal to one million and execute both() once.