How to get properties hasid/key with vertexes info in one gremlin query or Gremlin.Net - gremlin

I try to get properties which has key or id in following query by Gremlin.Net, but vertex info(id and label) in VertexProperty is null in result.
g.V().Properties<VertexProperty>().HasKey(somekey).Promise(p => p.ToList())
So i try another way, but it's return class is Path, and i had to write an ugly code for type conversion.
g.V().Properties<VertexProperty>().HasKey(somekey).Path().By(__.ValueMap<object, object>(true))
Is there a better way to achieve this requirement

I think basically the only thing missing to get what you want is the Project() step.
In order to find all vertices that have a certain property key and then get their id, label, and then all information about that property, you can use this traversal:
g.V().
Has(someKey).
Project<object>("vertexId", "vertexLabel", "property").
By(T.Id).
By(T.Label).
By(__.Properties<object>(someKey).ElementMap<object>()).
Promise(t => t.ToList());
This returns a Dictionary where the keys are the arguments given to the Project step.
If you instead want to filter by a certain property id instead of a property key, then you can do it in a very similar way:
g.V().
Where(__.Properties<object>().HasId(propertyId)).
Project<object>("vertexId", "vertexLabel", "property").
By(T.Id).
By(T.Label).
By(__.Properties<object>(someKey).ElementMap<object>()).
Promise(t => t.ToList());
This filters in both cases first the vertices to only have vertices that have the properties we are looking for. That way, we can use the Project() step afterwards to get the desired data back.
ElementMap should give all information back about the properties that you want.
Note however that these traversals will most likely require a full graph scan in JanusGraph, meaning that it has to iterate over all vertices in your graph. The reason is that these traversals cannot use an index which would make them much more efficient. So, for larger graphs, the traversals will probably not be feasible.
If you had the vertex ids available instead of the property ids in the second traversal, then you could make the traversal a lot more efficient by replacing g.V().Where([...]) simply with g.V(id).

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]

UPSERT an edge with properties with Gremlin

I'm trying to upsert an edge (insert if it does not exist but update if it does) with properties in Gremlin via a single query.
I have this which adds a manages edge with a duration property between two vertices with id of Amy and John.
g.E().where(outV().has('id','Amy')).where(inV().has('id','John')).fold().coalesce(unfold(),g.V('Amy').as('a').V('John').addE('manages').from('a').property('duration','1year')).
The query does do an upsert, but if I change the value of the duration property, remove the duration property, or add other properties, the property changes are not reflected on the edge.
I want to be able to change the value of the duration property without adding a new edge or having to remove the old one.
I'm fairly new to Gremlin so please share any advice which may help.
I'm not sure it matters but the underlying DB is an Azure Cosmos DB.
To always have the property change apply whether the edge exists or is created, you just need to move the property step to after the coalesce:
g.E().
where(outV().has('id', 'Amy')).
where(inV().has('id', 'John')).
fold().
coalesce(
unfold(),
g.V('Amy').as('a').
V('John').
addE('manages').from('a')).
property('duration', '1year')
However, that said, there are a few observations that can be made about the query. Starting with g.E() is likely to be inefficient and using g.V() mid traversal should be avoided, and where necessary just V() used.
If 'John" and 'Amy' are unique ID's you should take advantage of that along these lines:
g.V('Amy').
outE().where(inV().hasId('John')).
fold().
coalesce(
unfold(),
addE('manages').from(V('Amy')).to(V('John'))).
property('duration', '1year')
Two additions to Kevin's answer:
I think you need to specify the edge label in outE, otherwise the unfold may return other relationships present between the two vertices, and these will be updated with the property, rather than triggering the addE of the new edge. Specifying the edge label should ensure the length of the folded array is 0 in the case of INSERT and 1 in the case of UPDATE.
For Cosmos DB Gremlin API, use the anonymous class __ when not using g
g.V('Amy').
outE('manages').where(inV().hasId('John')).
fold().
coalesce(
unfold(),
__.addE('manages').from(__.V('Amy')).to(__.V('John'))).
property('duration', '1year')
More detailed example here.

Gremlin code to find 1 vertex with specific property

I want to return a node where the node has a property as a specific uuid and I just want to return one of them (there could be several matches).
g.V().where('application_uuid', eq(application_uuid).next()
Would the above query return all the nodes? How do I just return 1?
I also want to get the property map of this node. How would I do this?
You would just do:
g.V().has('application_uuid', application_uuid).next()
but even better would be the signature that includes the vertex label (if you can):
g.V().has('vlabel', 'application_uuid', application_uuid).next()
Perhaps going a bit further if you explicitly need just one you could:
g.V().has('vlabel', 'application_uuid', application_uuid).limit(1).next()
so that both the graph provider and/or Gremlin Server know your intent is to only next() back one result. In that way, you may save some extra network traffic/processing.
This is a very basic query. You should read more about gremlin. I can suggest Practical Gremlin book.
As for your query, you can use has to filter by property, and limit to get specific number of results:
g.V().has('application_uuid', application_uuid).limit(1).next()
Running your query without the limit will also return a single result since the query result is an iterator. Using toList() will return all results in an array.

Gremlin bredcrumb query

I'm new to Gremlin and still learning.
I'd like to include the starting vertex in the results of the following:
g.V('leafNode').repeat(out()).emit()
This gives me a collection of vertexes starting from an arbitrary leaf node "upwards" to the root vertex. However this collection excludes the V('leafNode') vertex itself.
How do I include the V('leafNode') in this collection?
Thanks
-John
There are two places for the emit in this statement: either before the repeat or after. If it comes before the repeat, it will be performed before evaluating the next loop.
Source: http://tinkerpop.apache.org/docs/current/reference/#repeat-step
So the following should take care of what your request.
g.V('leafNode').emit().repeat(out())

How to get an attribute named ID in gremlin

I'm getting weird results while writing a gremlin query. I can happily use the has function for most of the attributes for my nodes, for example "().has('name', 'VerisignCzagExtension').property('id')" will return v5086. But when I attempt to use the has function with the attribute id it never returns true. for example "().has('id', 'v5086').property('id')" returns no results. Anyone have any idea why this is happening?
Thanks.
Internally, Neo4j stores all IDs as java.lang.Long objects. This is a special behavior for id property only. All other properties are stored with their implied data types. That's a reason why has('name', 'VerisignCzagExtension') works (because name property is excluded from this special behavior meant for id). I'm assuming v5086 is being type casted to java.lang.Long, thus losing it's real value. That could explain zero results after a has('id', 'v5086') Gremlin step.
AFAIK, id property is immutable (can't be changed). If you need to make id look ups for vertices using a has Gremlin step, it would look something like has('id', 5086L) assuming that the vertex id is 5086 and is being stored as a java.lang.Long value. An extra L is for explicit java.lang.Long type-casting, Neo4j would assume java.lang.Integer if you don't add that L and your Gremlin step would result in zero results again.
Finally, you might want to call your named ID something else, like a property with key name.
Hope this helps.

Resources