1

I'm trying to find the shortest path taking into consideration the weights properties on the edges my work is on TinkerGraph and i want to do it in java.

gremlin is not very helpful for me

g.V().has(id1).
  repeat(both().simplePath()).
    until(has(id2)).as("path").
  map(unfold().coalesce(values("weight"),
                        constant(0)).
      sum()).as("cost").
  select("cost","path").next().get("path");

this gives me the shortest path without taking into consideration the weight property on the edges .

EDITED: my example:

edges inserted:

source,target

b1,b2

b1,b2

b1,b2

b1,b2

b1,b3

b3,b2

private void add(Vertex source,Vertex target){
    if(!checkEdgeExist(graph,source,target))
        source.addEdge(target).property(WEIGHT,1.0);
    else {
        Edge e = getEdgeBetweenTwoVertices(graph,source,target);
       source.edges(Direction.OUT).forEachRemaining(edge -> {
            if(edge.inVertex().equals(target))
                edge.property(WEIGHT,(double)e.property(WEIGHT).value()+1);
        });

    private  static  boolean checkEdgeExist(TinkerGraph graph,Vertex source,Vertex target){
    return graph.traversal().V(source).outE().filter(p -> p.get().inVertex().equals(target)).hasNext();
}

in other words the weight of the edge gets updated according to the frequency of an edge, for example if b1,b2 appeared 4 time the edge will be of weight 4.Now i want Dijkstra to return the shortest path in terms of weight and not the shortest in terms of edges. path(b1,b2) = b1->b3->b2

alaa elias
  • 11
  • 5
  • please, consider adding what you achieved – Gratien Asimbahwe Nov 14 '18 at 09:48
  • Welcome to SO ;) Please read this article on [how to ask a good question](https://stackoverflow.com/help/how-to-ask). This would include a proper description of what you are trying to achieve, your code (or the relevant snippets) as well as your efforts showing what you have tried so far and possible error messages. – iLuvLogix Nov 14 '18 at 09:50

2 Answers2

2

Your Gremlin is close to being right but you're missing something things. I tested on the "modern" toy graph that ships with TinkerPop and you should find that this works:

gremlin> g.V().has('person','name','marko').
......1>   repeat(bothE().otherV().simplePath()).
......2>     until(has('software','name','ripple')).
......3>   path().as("path").
......4>   map(unfold().coalesce(values("weight"),
......5>                         constant(0)).sum()).as("cost").
......6>   select("cost","path")
==>[cost:2.0,path:[v[1],e[8][1-knows->4],v[4],e[10][4-created->5],v[5]]]
==>[cost:1.8,path:[v[1],e[9][1-created->3],v[3],e[11][4-created->3],v[4],e[10][4-created->5],v[5]]]

The key pieces you were missing were:

  1. You needed to replace both() in your repeat() with bothE().otherV() so that the edges would be accounted for.
  2. Following on from the previous item, you needed the edges so that they would appear in the call to path() on line 3 that was also missing - with item 1 the Path would only contain vertices. If you look at line 4, you can see why that is important because the Path is unfolded and the "weight" properties summed for that Path which gives you "cost".

Note that when TinkerPop 3.4.0 releases, "shortest path" becomes a core step which should make such operations much more straightforward.

stephen mallette
  • 45,298
  • 5
  • 67
  • 135
  • Thanks for the response , I've tried running the code but i am still getting the shortest path and not the path with the least weight. is there something i'm missing? – alaa elias Nov 15 '18 at 16:05
  • if you're using something other than the modern toy graph that i was using above I guess you'd have to share a data sample that demonstrates your problem - add a script like this one to your question: https://stackoverflow.com/questions/51388315/gremlin-choose-one-item-at-random – stephen mallette Nov 15 '18 at 16:25
  • I'm using the tinkergraph in java , i keep getting the shortest path and displayed the cost of the path and it was higher than that i got when i removed this specific shortest path . my main purpose is to run Dijkstra alike algorithm in tinkerpop and not BFS – alaa elias Nov 15 '18 at 16:49
  • please provide a script that demonstrates the problem or demonstrate your problem in the context of the modern graph that i used if you can do that. if you can update your question with that information i can try to take this further but at this point it's not clear to me as to where things are going wrong – stephen mallette Nov 15 '18 at 17:51
  • g.V(1).repeat(outE().inV().simplePath()).until(hasId(5)). path().as('p'). map(unfold().coalesce(values('weight'), constant(0.0)).sum()).as('cost'). select('cost','p') //(4) I've found this in gremlin documentation . can you provide me with the same code in java ? as it seems to me its not the same – alaa elias Dec 12 '18 at 15:39
  • it's the same. should work fine as long as you static import `__` class for those anonymous inner traversals. – stephen mallette Dec 12 '18 at 15:56
0

According to your description, this is your test graph:

g = TinkerGraph.open().traversal()
g.addV().property(id, 'b1').as('b1').
  addV().property(id, 'b2').as('b2').
  addV().property(id, 'b3').as('b3').
  addE('link').
    from('b1').
    to('b2').
    property('weight', 4).
  addE('link').
    from('b1').
    to('b3').
    property('weight', 1).
  addE('link').
    from('b3').
    to('b2').
    property('weight', 1).
  iterate()

The shortest weighted directed path is found using this query:

gremlin> g.withSack(0).V('b1').
......1>   repeat(outE().sack(sum).by('weight').inV().simplePath()).
......2>     emit(hasId('b2')).
......3>   order().
......4>     by(sack()).
......5>   limit(1).
......6>   path().
......7>     by(id).
......8>     by('weight')
==>[b1,1,b3,1,b2]
Daniel Kuppitz
  • 10,846
  • 1
  • 25
  • 34
  • I've tried to write the gremlin code above in java , but could not find an option to fit Sack(sum()) – alaa elias Nov 22 '18 at 08:49
  • can you provide me with java syntax if what you are doing in gremlin ? – alaa elias Nov 22 '18 at 09:41
  • There is no `sum()` in `sack()`, it's `Operator.sum`. – Daniel Kuppitz Nov 22 '18 at 18:26
  • g.V(1).repeat(outE().inV().simplePath()).until(hasId(5)). path().as('p'). map(unfold().coalesce(values('weight'), constant(0.0)).sum()).as('cost'). select('cost','p') //(4) I've found this in gremlin documentation . can you provide me with the same code in java ? as it seems to me its not the same – alaa elias Dec 12 '18 at 15:38
  • There is no real difference in Java. Just make the imports and replace single quotes with double quotes. – Daniel Kuppitz Dec 12 '18 at 15:58