Add different values to each of multiple vertices - gremlin

I know that I can select multiple specific vertices by id in a single step, for example (using gremlin-python syntax):
g.V([1, 2, 3]).next()
>>> [v[1], v[2], v[3]]
How can I then add a property with different values to each of these selected items? For example, I would like that:
Vertex 1 has property 'x' with value 'a'
Vertex 2 has property 'x' with value 'b'
Vertex 3 has property 'x' with value 'c'
So I'd like to be able to say something like:
g.V([1, 2, 3]).<add property 'x' with values ['a', 'b', 'c']>.next()
Is it possible?

You could use choose() to accomplish something like that which will give you if-then-else type branching. Using the modern toy graph that ships with TinkerPop distributions:
gremlin> g.V(1,2,3).
......1> choose(id()).
......2> option(1, property('switch','a')).
......3> option(2, property('switch','b')).
......4> option(3, property('switch','c')).iterate()
gremlin> g.V(1,2,3).
......1> project('id','switch').
......2> by(id).
......3> by('switch')
==>[id:1,switch:a]
==>[id:2,switch:b]
==>[id:3,switch:c]
As of TinkerPop 3.3.3, you could also do something like this which uses a side-effect:
gremlin> g.withSideEffect('x',[1:'a',2:'b',3:'c']).
......1> V(1,2,3).as('v').
......2> property('switch', select('x').
......3> select(select('v').id()))
==>v[1]
==>v[2]
==>v[3]
gremlin> g.V(1,2,3).
......1> project('id','switch').
......2> by(id).
......3> by('switch')
==>[id:1,switch:a]
==>[id:2,switch:b]
==>[id:3,switch:c]
You need 3.3.3+ because you need the ability to select() runtime generated keys which was only added in that version.
I don't think you can use the key of the Map of "x" to handle the lookup of the vertex without a lambda (maybe i'm not thinking of something simple), so unfortunately you have to specify the ids twice, but you could parameterize that pretty easily because you just need to construct the Map and then grab the .keys() from it to give to V().

Related

Using a back step to get two connected vertexes

If I have 3 vertex's A, B, C, where B has an edge to A and C. Starting with B how can I get values for A and C
g.V("b").out("toC").as("c").out("toA").as("a").select("c", "a").next()
This is what I have but it causes an error because I don't think you can go out to A from C since they aren't connected. I need a way to go back to B first but there is no back step that I have seen.
Using this graph
gremlin> g.addV('A').as('a').
......1> addV('B').as('b').
......2> addV('C').as('c').
......3> addE('toA').from('b').to('a').
......4> addE('toC').from('b').to('c')
==>e[42783][42780-toC->42781]
You can find the vertices connected to B using
gremlin> g.V().hasLabel('B').out().elementMap()
==>[id:42774,label:A]
==>[id:42776,label:C]
You can also filter using specific edge labels in cases where there are lots of edges from B and you only want specific ones:
gremlin> g.V().hasLabel('B').out('toA','toC').elementMap()
==>[id:42774,label:A]
==>[id:42776,label:C]
If you really do need to write the query so that it works the way you showed in the question, then this is one way:
gremlin> g.V().hasLabel('B').as('b').
......1> out('toA').as('a').
......2> select('b').
......3> out('toC').as('c').
......4> select('a','c').
......5> by(elementMap())
==>[a:[id:42779,label:A],c:[id:42781,label:C]]
You can also try:
gremlin> g.V().hasLabel('B').
......1> outE().hasLabel('toA','toC').
......2> inV().elementMap()
==>[id:0,label:A]
==>[id:2,label:C]

longest path by weight in gremlin

i what will be the best query to get heaviest path b/w 2 nodes in a directed graph in gremlin?
*I do have multiple paths, and sometime longest path is not the heaviest.
where each edge (not node) has an integer attribute (weight). weight range is 0<= weight <=12
thanks.
In general, the sack step can be used for such calculations. Using the air-routes data set the query below finds the longest 3-hop routes between two airports using the dist property on the edges to calculate the weights. Notice that I limit my query to only find a certain number of results and use loops to specify a maximum depth I am interested in searching. Without such constraints queries like this can run for a very long time in a highly connected graph.
gremlin> g.withSack(0).
......1> V('3').
......2> repeat(outE().sack(sum).by('dist').inV().simplePath()).
......3> until(has('code','AGR').or().loops().is(4)).
......4> has('code','AGR').
......5> limit(5).
......6> order().
......7> by(sack(),desc).
......8> local(union(path().by('code').by('dist'),sack()).fold())
==>[[AUS,4901,LHR,4479,BOM,644,AGR],10024]
==>[[AUS,5294,FRA,4080,BOM,644,AGR],10018]
==>[[AUS,1520,JFK,7782,BOM,644,AGR],9946]
==>[[AUS,1500,EWR,7790,BOM,644,AGR],9934]
==>[[AUS,1357,YYZ,7758,BOM,644,AGR],9759]

Is there an efficient way to see how many edges and verticies were created in a gremlin Upsert?

Using a query like the following
g.V().has('person','name','marko').
fold().
coalesce(unfold(),
addV('person').property('name','marko')).
property('age',29)
Is there an efficient way to also return how many verticies were created?
I.e. 0 in the case that the marko vertex exists, 1 in the case that the marko vertex does not exist.
I think I'd go with union():
gremlin> g.V().has('person','name','marko').
......1> fold().
......2> union(coalesce(unfold(),
......3> addV('person').property('name','marko')).
......4> property('age',29),
......5> count(local))
==>v[1]
==>1
gremlin> g.V().has('person','name','darko').
......1> fold().
......2> union(coalesce(unfold(),
......3> addV('person').property('name','marko')).
......4> property('age',29),
......5> count(local))
==>v[13]
==>0
It's the reverse of what you asked for in terms of 1 and 0 existence but I suppose that would be easy enough to remedy if you really needed to but it would add additional complexity to the traversal around that count(local) which is pretty easy to read right now as it is.

Gremlin - if multiple vertices return multiple values each, how to limit the result to one per vertex

Essentially, I'm trying to modify the following piece of Gremlin code such that instead of operating on a single vertex at a time - signified by g.V(1), it will work with multiple vertices at once (e.g. changing to g.V()), while still only limiting the number of returned results per vertex to one (see limit(1)).
g.V(1).repeat(out().simplePath()).until(has('color', 'red')).path().limit(1)
The above query will compute the shortest path from a given vertex to the closest vertex which has property(color)==red.
However, I want to compute the shortest path for multiple vertices passed in at the same time, while still only returning a single path per vertex.
I'm having difficulty modifying this without returning multiple paths for the same vertex however.
Deduplicating the result by the start vertex should give you the expected result.
g.V().as('a').
repeat(out().simplePath()).
until(has('color', 'red')).
dedup('a').
path()
Example using the modern toy graph:
gremlin> g = TinkerFactory.createModern().traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> g.V().
......1> repeat(out().simplePath()).
......2> until(hasLabel('software')).
......3> path()
==>[v[1],v[3]]
==>[v[1],v[4],v[5]]
==>[v[1],v[4],v[3]]
==>[v[4],v[5]]
==>[v[4],v[3]]
==>[v[6],v[3]]
gremlin> g.V().as('a').
......1> repeat(out().simplePath()).
......2> until(hasLabel('software')).
......3> dedup('a').path()
==>[v[1],v[3]]
==>[v[4],v[5]]
==>[v[6],v[3]]

How to use less than inside option of CHOOSE step in gremlin

.choose(values('points')
.option(lt(500), updating the vertex properties)
.option(gt(500), updating and creating new properties)
.option(none,creating new vertex ))
points is vertex property of type integer
I want to perform less than and greater than operations inside option. I am trying in the above way.Please correct me if I am wrong.
If there is any other way to perform this please let me know.
Thank you
This feature hasn't been implemented as of Apache TinkerPop 3.4.2. It is a long standing open issue: TINKERPOP-1084. I think that if you want this functionality, you're going to have do a nested choose():
gremlin> g = TinkerFactory.createModern().traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> g.V().hasLabel('person').
......1> choose(values('age').is(lt(29)),
......2> constant('lt29'),
......3> choose(values('age').is(gt(29)),
......4> constant('gt29'),
......5> constant('29')))
==>29
==>lt29
==>gt29
==>gt29
Note that you aren't restricted to constant() as a result of these nested choose() operations. You can add any anonymous traversal you like there as in:
gremlin> g.V().hasLabel('person').
......1> choose(values('age').is(lt(29)),
......2> constant('lt29'),
......3> choose(values('age').is(gt(29)),
......4> math('_ - 29').by('age'),
......5> constant('29')))
==>29
==>lt29
==>3.0
==>6.0

Resources