Search code examples
gremlintinkerpoptinkerpop3

Tinkerprop Gremlin: Order by the weight of relations


Here is my test database:


    graph = TinkerGraph.open()
    g = graph.traversal()
    v1 = g.addV("person").property(id, 1).property("name", "1").next()
    v2 = g.addV("person").property(id, 2).property("name", "2").next()
    v3 = g.addV("person").property(id, 3).property("name", "3").next()
    v4 = g.addV("person").property(id, 4).property("name", "4").next()
    v5 = g.addV("person").property(id, 5).property("name", "5").next()
    v6 = g.addV("person").property(id, 6).property("name", "6").next()
    g.addE("knows").from(v1).to(v2).property(id, 10).property("weight", 0.4)
    g.addE("knows").from(v1).to(v2).property(id, 11).property("weight", 0.4)
    g.addE("knows").from(v1).to(v4).property(id, 12).property("weight", 0.2)
    g.addE("knows").from(v1).to(v6).property(id, 13).property("weight", 1)
    g.addE("knows").from(v2).to(v3).property(id, 14).property("weight", 0.4)
    g.addE("knows").from(v3).to(v5).property(id, 15).property("weight", 0.4)
    g.addE("knows").from(v4).to(v5).property(id, 16).property("weight", 0.4)
    g.addE("knows").from(v4).to(v5).property(id, 17).property("weight", 0.3)
    g.addE("knows").from(v6).to(v5).property(id, 18).property("weight", 0.4)
    g.addE("knows").from(v6).to(v5).property(id, 19).property("weight", 0.4)
    g.addE("knows").from(v6).to(v5).property(id, 20).property("weight", 0.2)

I'm trying to get shorters path (minimum sum of weight) from a person to another.

Here is my current query:


    g.V(1).repeat(bothE("knows").bothV()).until(hasId(6)).path().as("path").map(unfold().coalesce(values("weight"), constant(0)).sum()).as("Cost").select("path", "Cost").limit(10);
    ==>[path:[v[1],e[13][1-knows->6],v[6]],Cost:1]
    ==>[path:[v[1],e[10][1-knows->2],v[1],e[13][1-knows->6],v[6]],Cost:1.4]
    ==>[path:[v[1],e[11][1-knows->2],v[1],e[13][1-knows->6],v[6]],Cost:1.4]
    ==>[path:[v[1],e[12][1-knows->4],v[1],e[13][1-knows->6],v[6]],Cost:1.2]
    ==>[path:[v[1],e[13][1-knows->6],v[1],e[13][1-knows->6],v[6]],Cost:2]
    ==>[path:[v[1],e[10][1-knows->2],v[1],e[10][1-knows->2],v[1],e[13][1-knows->6],v[6]],Cost:1.8]
    ==>[path:[v[1],e[10][1-knows->2],v[1],e[11][1-knows->2],v[1],e[13][1-knows->6],v[6]],Cost:1.8]
    ==>[path:[v[1],e[10][1-knows->2],v[1],e[12][1-knows->4],v[1],e[13][1-knows->6],v[6]],Cost:1.6]
    ==>[path:[v[1],e[10][1-knows->2],v[1],e[13][1-knows->6],v[1],e[13][1-knows->6],v[6]],Cost:2.4]
    ==>[path:[v[1],e[10][1-knows->2],v[2],e[10][1-knows->2],v[1],e[13][1-knows->6],v[6]],Cost:1.8]

I'm not finding how to order by the Cost. I'm trying with the step order() and by("Cost") but it didn't works, it never return result. Here is one of my test that return nothing.

g.V(1).repeat(bothE("knows").bothV()).until(hasId(6)).path().as("path").map(unfold().coalesce(values("weight"), constant(0)).sum()).as("Cost").select("path").order().by(select("Cost")).limit(10);

Solution

  • Your query is running into an infinite loop. In your first query, you just got lucky as repeat() was aware of the limit() step and thus stopped after emitting 10 vertices. With order().by() included, repeat() can no longer do that as order().by() needs all results before it can order anything.

    Furthermore, there's a better way to keep track of the cost:

    g.withSack(0).V(1).
      repeat(bothE("knows").sack(sum).by("weight").otherV().simplePath()).
        until(hasId(6)).
      order().
        by(sack()).
      limit(10).
      path()