How to increment a vertex property value in a TinkerPop graph
Asked Answered
F

1

8

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.

Felt answered 9/12, 2016 at 15:20 Comment(0)
T
13

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().

Telamon answered 9/12, 2016 at 16:50 Comment(2)
Please note that Azure Cosmos Graph DB does not support sack nor the solution with union as of June 2019.Webbed
Since Azure still does not support those things, I just want to mention, that a workaround can be to use. The function property(list, 'age', 1) works in Azure and will create a list property named 'age' if it doesn't already exist and then it will, in this case, add '1' to that list. You would then have to do a sum on the property to get the actual value, when you do queries.Cide

© 2022 - 2024 — McMap. All rights reserved.