Akaedintov
Akaedintov

Reputation: 795

Can't traverse to vertices with unique properties in Gremlin

I'm looking for paths to get from one vertex to the other, avoiding vertices with properties already matched on that path.

Consider this example:

    Graph graph = TinkerGraph.open();

    GraphTraversalSource t = graph.traversal();

    Vertex A = t.addV().property("age", 19).next();
    Vertex B = t.addV().property("age", 21).next();
    Vertex C = t.addV().property("age", 20).next();
    Vertex D = t.addV().property("age", 21).next();
    Vertex E = t.addV().property("age", 22).next();

    t.V(A).addE("knows").to(B).iterate();
    t.V(B).addE("knows").to(C).iterate();
    t.V(C).addE("knows").to(D).iterate();
    t.V(D).addE("knows").to(E).iterate();
    t.V(C).addE("knows").to(E).iterate();

    List<Path> paths = t.V(A)
            .repeat(
                    out()
            ).times(5).emit()
            .has("age", 22).path().toList();

    Assert.assertEquals(1, paths.size());

I'm looking for ways to go from A to E. There are two paths:

A->B->C->D->E A->B->C->E

What I'm looking for is just the second one, because in the first path, B and D has the same age.

I tried to filter using as and by, but I failed to scale that to whole path. For instance, I can check the vertices not to match the first vertex' property, by doing the following:

    List<Path> paths = t.V(A).as("first")
            .repeat(
                    out()
                    .where(P.neq("first")).by("age")
            ).times(5).emit()
            .has("age", 22).path().toList();

    Assert.assertEquals(1, paths.size());

But as you can imagine, it doesn't filter the collisions in the middle of the path. I feel like there should be an easier way to do this that I'm missing. Is there a statement like as(), but instead of replacing the previous assignment, it keeps them in an array or something? How can I achieve this?

Thanks

Upvotes: 1

Views: 424

Answers (1)

Daniel Kuppitz
Daniel Kuppitz

Reputation: 10904

You need to compare the current age against all previously seen ages. If there's any match, let the traverser die:

t.V(A).as("a").
  repeat(filter(loops().is(lt(5))).out().
         not(values("age").as("current").         /* current age   */
               select(all, "a").unfold().         /* previous ages */
               values("age").
                 where(eq("current"))).as("a")).  /* not() negates the match */
    until(has("age", 22)).
  path()

Upvotes: 2

Related Questions