Search code examples
gremlintinkerpopamazon-neptune

Neptune Gremlin how to break cycles when collecting paths


I have the following graph:

enter image description here

Created using:

g.addV("Person").property(T.id, "1").as("p1")
        .addV("Person").property(T.id, "2").as("p2")
        .addV("Person").property(T.id, "3").as("p3")
        .addV("Person").property(T.id, "4").as("p4")
        .addV("Person").property(T.id, "5").as("p5")
        .addV("Person").property(T.id, "6").as("p6")
        .addV("Person").property(T.id, "7").as("p7")
        .addE("TalksTo").from("p1").to("p2").property(T.id, "a")
        .addE("TalksTo").from("p2").to("p3").property(T.id, "b")
        .addE("TalksTo").from("p3").to("p2").property(T.id, "c")
        .addE("TalksTo").from("p2").to("p4").property(T.id, "d")
        .addE("TalksTo").from("p4").to("p5").property(T.id, "e")
        .addE("TalksTo").from("p5").to("p7").property(T.id, "f")
        .addE("TalksTo").from("p6").to("p5").property(T.id, "g")
        .addE("TalksTo").from("p3").to("p6").property(T.id, "h")

I would like to traverse that graph to get the following paths:

7 -> 5 -> 4 -> 2 -> 1
7 -> 5 -> 6 -> 3 -> 2 -> 1

Essentially breaking up the cycle between 2 and 1.

I have tried with the following query:

    g.V("7")
    .repeat(
        as("source").inE("TalksTo").outV().where(neq("source"))
     )
    .until(or(
        inE().hasLabel("TalksTo").count().is(0),
        loops().is(10),
        cyclicPath()
     ))
    .path()
    .toList();

But it does not yield the results I am looking for - do I need to consider subgraphs to solve this?


Solution

  • You want to use simplePath() filter.

    ......1>   repeat(inE('TalksTo').outV().simplePath()).
    ......2>     until(
    ......3>       or(
    ......4>         inE().hasLabel("TalksTo").count().is(0),
    ......5>         loops().is(10))).
    ......6>   path().by(T.id)
    ==>[7,f,5,e,4,d,2,a,1]
    ==>[7,f,5,g,6,h,3,b,2,a,1]
    

    To get the exact path as posted in your question , you can directly hop to the vertex instead of first getting an edge and then the vertex :

    ......1>   repeat(in('TalksTo').simplePath()).
    ......2>     until(
    ......3>       or(
    ......4>         inE().hasLabel("TalksTo").count().is(0),
    ......5>         loops().is(10))).
    ......6>   path().by(T.id)
    ==>[7,5,4,2,1]
    ==>[7,5,6,3,2,1]