Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to increment a vertex property value in a TinkerPop graph

How would I traverse through a graph and increment a value of a vertex property? Either by some fixed amount or by an amount in a property of an edge leading to it.

eg. with the following graph:

gremlin> graph = TinkerGraph.open()
==>tinkergraph[vertices:0 edges:0]
gremlin> g = graph.traversal()
==>graphtraversalsource[tinkergraph[vertices:0 edges:0], standard]
gremlin> a = g.addV('name','a','amount', 100).next()
==>v[0]
gremlin> b = g.addV('name','b','amount', 200).next()
==>v[3]
gremlin> c = g.addV('name','c','amount', 300).next()
==>v[6]
gremlin> a.addEdge('fill', b, 'bonus', 20)
==>e[9][0-drain->3]
gremlin> b.addEdge('fill', c, 'bonus', 40)
==>e[10][3-drain->6]
gremlin> 

so

1) How would I increment each vertex by 10?

at the end I want to have:

gremlin> g.V().valueMap()
==>[amount:[110],name:[a]]
==>[amount:[210.0],name:[b]]
==>[amount:[310.00],name:[c]]

Given the statement:

g.V(a).property('amount', X)

I guess I'm trying to do something like:

g.V(a).property('amount', g.V(a).values('amount').next()+10)

...but for all vertices in my graph. It looks like Tinkerpop2 had loop() and it.object that might have helped, but seems not in Tinkerpop3

Edit: OK, I am closer, but not quite there:

gremlin> g.V().as('x').property('amount', select('x').by('amount')+10)
No signature of method: org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal.plus() is applicable for argument types: (java.lang.Integer) values: [10]
Possible solutions: sum(), take(int), sum(groovy.lang.Closure), is(java.lang.Object), use([Ljava.lang.Object;), drop(int)
Type ':help' or ':h' for help.
Display stack trace? [yN]

2) How would I increment each vertex by the value of the bonus property in the fill edge leading to it.

at the end I want to have:

gremlin> g.V().valueMap()
==>[amount:[100],name:[a]]
==>[amount:[220.0],name:[b]]
==>[amount:[340.00],name:[c]]

I tried using a sack to do it, but couldn't quite work it out as a sack accumulates the data throughout the traversal. I tried to put the withSack within the repeat clause to try and create a new sack, but that didn't work. I don't see how I can 'pass' the value of a property from one vertex to an operation on the next vertex.

like image 546
Matt Hamilton Avatar asked Dec 09 '16 15:12

Matt Hamilton


1 Answers

Let me use TinkerPop's toy graph, so it's easier for others to follow. The toy graph contains 4 person vertices which have an age property:

gremlin> g = TinkerFactory.createModern().traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> g.V().has("age").valueMap()
==>[name:[marko],age:[29]]
==>[name:[vadas],age:[27]]
==>[name:[josh],age:[32]]
==>[name:[peter],age:[35]]

To answer your first question, let's add a constant value (10):

gremlin> g.V().has("age").
           property("age", union(values("age"), constant(10)).sum()).valueMap()
==>[name:[marko],age:[39]]
==>[name:[vadas],age:[37]]
==>[name:[josh],age:[42]]
==>[name:[peter],age:[45]]

Another technique to do this is the use of sack()s:

gremlin> g.withSack(0).V().has("age").
           sack(assign).by("age").sack(sum).by(constant(10)).
           property("age", sack()).valueMap()
==>[name:[marko],age:[39]]
==>[name:[vadas],age:[37]]
==>[name:[josh],age:[42]]
==>[name:[peter],age:[45]]

Now to your second question about adding a dynamic value, coming from incident edges. In the toy graph we have a weight property on every edge, so let's use it:

gremlin> g.V().has("age").
           property("age", union(values("age"), bothE().values("weight")).sum()).valueMap()
==>[name:[marko],age:[30.9]]
==>[name:[vadas],age:[27.5]]
==>[name:[josh],age:[34.4]]
==>[name:[peter],age:[35.2]]

And again you could also use sack():

gremlin> g.withSack(0).V().has("age").
           sack(assign).by("age").sack(sum).by(bothE().values("weight").sum()).
           property("age", sack()).valueMap()
==>[name:[marko],age:[30.9]]
==>[name:[vadas],age:[27.5]]
==>[name:[josh],age:[34.4]]
==>[name:[peter],age:[35.2]]

So the ultimate question is: Should one technique preferred over the other? I'd say yes, sack() should be your choice - the traversals are longer in terms of what you have to type, but look at the .profile() output, sack() can easily outperform union().

like image 195
Daniel Kuppitz Avatar answered Sep 18 '22 22:09

Daniel Kuppitz