Is it possible to tell whether a Gremlin Drop() step did anything? - gremlin

I have a traversal that ends with a drop() to delete a vertex. I would like to be able to tell the difference between the drop() removing a vertex and the traversal just not matching anything.
I tried adding an alias to one of the earlier nodes and select()ing it at the end of the traversal, but that doesn't return anything even when the traversal does match the graph.
e.g.
g.V('id', '1').as('flag')
.out('has_child')
.drop()
.select('flag')
.toList()

The trick is that drop() is a filter step so it removes objects from the traversal stream. You can work around that situation a bit by dropping by sideEffect():
gremlin> g.V().has('person','name','marko')
==>v[1]
gremlin> g.V().has('person','name','marko').sideEffect(drop())
==>v[1]
gremlin> g.V().has('person','name','marko')
gremlin>
The return of the vertex would mean that it was present and dropped, but if no value is returned then it wasn't present in the first place to be dropped.

Related

Gremilin select Id from elementMap to get the vertex by id

I try to get a vertex by an id which is in a element map. Something like
g.V(g.V().limit(1).elementMap().as(‘map’).select(‘map’).by(‘id’))
This is just a simplified example I must use the elementMap since I get an elementMap from an union result where I must use elementMap to order the vertices by specific properties which might be not available in a vertex.
And what I don’t understand at all is why selecting id or label returns null, while selecting an other property from the map of the vertex works.
g.V().limit(1).elementMap().as(‘map’).select(‘map’).by(‘id’)
==>null
g.V().limit(1).elementMap().as(‘map’).select(‘map’).by(‘key’)
==>value
So how can I achieve selecting the id in the elementMap to get the vertex for that id?
gremlin> g.V(
g.V().limit(1).elementMap().unfold()
.where(select(keys).is(eq(id))).select(values).next() )
==>v[1]
Things got confusing because your original query had three issues:
You have to next() the inner traversal to get a value rather than the value wrapped in an iterating GraphTraversal. Note that the gremlin console does next() automatically for the outer traversal.
The by() modulator on the elementMap only works on the values of the Map
Although the ElementMap seems to show an 'id' string as key it actually is the id token defined by TinkerPop
Finally note that you may not need the elementMap step at all and do the query like this:
gremlin> g.V(g.V().limit(1).id().next())
==>v[1]
[This answer was significantly extended after the comments below]

Gremlin query to check if a value exists in the given external map

I would like to traverse the graph until my node property value exist in the set. Set contains id of the nodes and trivial objects.
The query is like:
public Map<String,Object> getNodes( Long startNodeID, Set<String, TraversedNode> mySet){
return g.withSideEffect("x",mySet).V(startNodeID)
.repeat( ...something )
.choose( ...something )
.until( myProperty is found in the given set )
}
I have tried many things in the until part but couldn't get it. Any suggestions to achieve? It maybe related to values and where keywords.
values("id").where(P.within("x")) doesn't work
Using the air-routes graph as sample data, a simple query can be written that looks for IDs within a provided set, as the query progresses. As mentioned in the comments, it is not 100% clear if this is what you are looking for but perhaps it will help with follow on questions.
gremlin> g.withSideEffect('s',[48,54,62,12]).
......1> V(44).
......2> repeat(out().simplePath()).
......3> until(where(within('s')).by(id).by()).
......4> path().
......5> limit(5)
==>[v[44],v[8],v[48]]
==>[v[44],v[8],v[54]]
==>[v[44],v[8],v[12]]
==>[v[44],v[13],v[12]]
==>[v[44],v[13],v[48]]
It may appear that you should just be able to do until(hasId(within('s'))), but in that case 's' is treated as the literal string "s" and not a symbol representing the set called s. When a predicate is nested inside a where step, as in where(within('s')), Gremlin treats that as a special case and will treat s as the name of something declared earlier.

is it possible to declare a variable with gremlin node values and later traverse using the variable

I wonder if gremlin can handle a data structure graph where you can save the reference to the node in a variable and later use it to traverse neighboring nodes.
node1= g.V(1)
node1.out('knows')
There are two confusing aspects here:
A Traversal is a kind of Iterator that can only be used once
The Gremlin Console iterates each Traversal for a significant (configurable) number of times
The second aspect can be prevented with the code example below. The first aspect makes the answer to your question a practical "no". Of course you can code some kind of abstraction that fulfills your needs yourself.
gremlin> node1 = g.V(1); null
==>null
gremlin> node1.class
==>class org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal
gremlin> contacts = node1.out('knows'); null
==>null
gremlin> contacts
==>v[2]
==>v[4]
gremlin> contacts
gremlin>

The provided traversal does not map to a value

I am trying to execute a math query.
gts.V()
.hasLabel("account")
.has("id",42)
.both("account_label1").as("label1")
.and(__.identity()
.project("a","b")
.by(__.identity()
.both("label1_label2")
.both("label2_label3")
.values("createTime"))
.by(__.identity()
.both("label1_label4")
.both("label4_label5")
.values("launchTime"))
.math("floor((a-b)/(86400))").is(100))
.select("label1")
.toList()
Above query fails with error
The provided traverser does not map to a value: v[137]->[IdentityStep, VertexStep(BOTH,[label1_label2],vertex), VertexStep(BOTH,[label2_label3],vertex), NoOpBarrierStep(2500), PropertiesStep([createTime],value)]
Why is gremlin injection NoOpBarrierStep?
What is the meaning of the NoOpBarrierStep(2500)?
What will be the correct gremlin query for the same?
When you use project() it expects a value for each by() modulator and that value should not produce an empty Iterator. Here's a simple example:
gremlin> g = TinkerFactory.createModern().traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> g.V().project('x').by(out())
==>[x:v[3]]
The provided traverser does not map to a value: v[2]->[VertexStep(OUT,vertex)]
Type ':help' or ':h' for help.
Display stack trace? [yN]
The first vertex is able to traverse out() but the next one processed by project() has no outgoing edges and therefore produces this error. In your case, that simply means that not all of your traversers can traverse both().both() or if they can, you would want to be sure that they all had "createTime" property values. Either of those scenarios could cause the problem.
You could fix this in a variety of ways. Obviously, if it's a data problem you could simply fix your data and always assume that the traversal path is right. If that's not the case, you need to write your Gremlin to be a bit more forgiving if the traversal path is not available. In my case I could do:
gremlin> g.V().project('x').by(out().fold())
==>[x:[v[3],v[2],v[4]]]
==>[x:[]]
==>[x:[]]
==>[x:[v[5],v[3]]]
==>[x:[]]
==>[x:[v[3]]]
Perhaps in your case you might do:
by(coalesce(both("label1_label2").both("label2_label3").values("createTime"),
constant('n/a')))
Note that you do not need to specify identity() for the start of your anonymous traversals.
Finally, in answer to your questions about NoOpBarrierStep, that step is injected into traversals where Gremlin thinks it can take advantage of a bulking optimization. You can add them yourself with barrier() step as well. Here's a quick description of "bulking" as taken from the TinkerPop Reference Documentation:
The theory behind a "bulking optimization" is simple. If there are one million traversers at vertex 1, then there is no need to calculate one million both()-computations. Instead, represent those one million traversers as a single traverser with a Traverser.bulk() equal to one million and execute both() once.

Gremlin: how to overcome property null problem and write a query which updates all properties of a certain vertex?

I need to write a single Gremlin query that can set the new property values of a vertex. All the property names are known in advance (in this example: Type, Country, Status). Some of the property values can be null - and I don't know which ones in advance. The query should work for all cases. For example, let's say I currently have this query:
g.V(123).
property('Type',Type).
property('Country',Country).
property('Status',Status)
This query works fine if all the parameter (Type, Country, Status) values are non-null. If, say, Country is null, I get an error:
The AddPropertyStep does not have a provided value: AddPropertyStep({key=[Country]})
In such case I would need to use a different query to drop the property (by the way, is there a better way for dropping a property?):
g.V(123).
property('Type',Type).
property('Status',Status).
properties('Country').drop()
Is it possible to write a universal query that can handle both null and non-null values? I cannot use console or programming, just a single Gremlin query to be executed.
Thanks!
TinkerPop doesn't allow null values in properties (though you might find some graph databases allowing different semantics there, I suppose), so you should validate your data up front to ensure that it has some meaningful "empty value" as opposed to a null. If you can't do that for some reason, I guess you could use choose() step to "check for null":
gremlin> g = TinkerFactory.createModern().traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> g.V().has('person','name','marko').valueMap()
==>[name:[marko],age:[29]]
gremlin> age = null
gremlin> g.V().has('person','name','marko').choose(constant(age).count().is(0), properties('age').drop(),property('age',age))
gremlin> g.V().has('person','name','marko').valueMap()
==>[name:[marko]]
gremlin> age = 30
==>30
gremlin> g.V().has('person','name','marko').choose(constant(age).count().is(0), properties('age').drop(),property('age',age))
==>v[1]
gremlin> g.V().has('person','name','marko').valueMap()
==>[name:[marko],age:[30]]
The check for "is null" is basically just: constant(age).count().is(0), which leans on the Gremlin's semantics for null values in a stream being empty and giving a count() of zero. It works, but it makes your Gremlin a little less readable. That might be a nice DSL step to add if you have to write that a lot.

Resources