Concatenate Gremlin GraphTraversal result with string - gremlin

In this very simple example I am trying to add a new vertex which should be labeled like an existing vertex but with some prefix attached:
g.V(1).addV('prefix_' + label()).valueMap(true)
What am I missing here? It's clearly not a String, but how would I serialize that?
gremlin> g.V(1).label()
==>Person
gremlin> g.V(1).constant(label())
==>[LabelStep]

Gremlin today does not provide a built in string concatenation function. It would be nice if it did. That means your best alternative today is to use an in line closure/lambda. Here is an example using TinkerGraph and the air-routes graph.
gremlin> g.V(3).map {"prefix_" + it.get().label}.as('a').addV(select('a'))
==>v[60867]
gremlin> g.V(60867).label()
==>prefix_airport
Note that not all graph databases allow closures so this cannot be assumed to work universally on any TinkerPop enabled Graph DB backend.

Related

Need a query to retrieve complete graph

I am trying to retrieve all the node and properties details in parent-child hierarchy.
Nested within each other.
Since I am new with gremlin, graphDB I am having really tough time to get it done.
Please suggest a solution and if you could walk me through it, it will be great.
Following is my structure
And I am trying to keep the response as clean as possible.
I am using cosmosDB and Gremlin.
NET api for this.
I tried the following but it gave me response in key value,
g.V("some_id").repeat(out()).emit().tree().path()
g.V("some_id").emit().repeat(both().simplePath()).dedup()
please any kind of suggestion would be great.
I"m not sure what format you want your result, but use of path(), tree() or subgraph() would typically give you the graph structure. Since you are using CosmosDB, you're only options are path() and tree() as subgraph() does not appear to be supported.
Using this sample graph as a simple tree:
g.addV().property(id, '1').as('1').
addV().property(id, '2a').as('2a').
addV().property(id, '2b').as('2b').
addV().property(id, '3a').as('3a').
addV().property(id, '4a').as('4a').
addE('child').from('1').to('2a').
addE('child').from('1').to('2b').
addE('child').from('2a').to('3a').
addE('child').from('3a').to('4a')
you can see the effect of path() which basically gathers the contents of each step Gremlin took:
gremlin> g.V('1').repeat(out()).emit().path()
==>[v[1],v[2a]]
==>[v[1],v[2b]]
==>[v[1],v[2a],v[3a]]
==>[v[1],v[2a],v[3a],v[4a]]
Since I used out() we don't see the edges, but that is easily remedied by adding making a small adjustment to directly consume edges into the path history:
gremlin> g.V('1').repeat(outE().inV()).emit().path()
==>[v[1],e[0][1-child->2a],v[2a]]
==>[v[1],e[1][1-child->2b],v[2b]]
==>[v[1],e[0][1-child->2a],v[2a],e[2][2a-child->3a],v[3a]]
==>[v[1],e[0][1-child->2a],v[2a],e[2][2a-child->3a],v[3a],e[3][3a-child->4a],v[4a]]
Taken together with duplication removed on your application side you have a complete graph with path().
Replacing path() with tree() will essentially do that deduplication by maintaining the tree structure of the path history:
gremlin> g.V('1').repeat(out()).emit().tree()
==>[v[1]:[v[2b]:[],v[2a]:[v[3a]:[v[4a]:[]]]]]
gremlin> g.V('1').repeat(outE().inV()).emit().tree()
==>[v[1]:[e[0][1-child->2a]:[v[2a]:[e[2][2a-child->3a]:[v[3a]:[e[3][3a-child->4a]:[v[4a]:[]]]]]],e[1][1-child->2b]:[v[2b]:[]]]]
The Tree is just represented as a Map where each key represents a like a root and value is another Tree (i.e. the branches from it). It is perhaps better visualized this way:
gremlin> g.V('1').repeat(out()).emit().tree().unfold()
==>v[1]={v[2b]={}, v[2a]={v[3a]={v[4a]={}}}}
gremlin> g.V('1').repeat(out()).emit().tree().unfold().next().value
==>v[2b]={}
==>v[2a]={v[3a]={v[4a]={}}}
If neither of these structures are suitable and subgraph() is not available you can technically just capture and return the edges you traverse as the low level elements of your subgraph as described in this blog post.
Given the comments on this answer I also present the following option which used group():
gremlin> g.V('1').emit().
......1> repeat(outE().group('a').by(outV()).by(inV().fold()).inV()).cap('a').unfold()
==>v[1]=[v[2a], v[2b]]
==>v[3a]=[v[4a]]
==>v[2a]=[v[3a]]
It's not exactly a "tree" but if you know the root (in this case v[1]) you can find its key in the Map. The values are the children. You can then look up each of those keys in the Map to find if they have children and so on. For example, we can lookup v[2b] and find that it has no children while looking up [v2a] reveals a single child of [v3a]. Gremlin can be pretty flexible in getting answers if you can be sorta flexible in how you deal with the results.

How to Generate TinkerPOP ByteCode?

I wonder if anyone can give me some pointers (that is where to start), on how to implement a translation from let say, a query language A to TinkerPop Graph Traversal. Let assume that A semantic intuitively translate to a subset of TinkerPop Traversal. In other words, what i am asking is:
Where Can I find the set instruction set of TinkerPOP Virtual Machine
What is TinkerPOP virtual Machine ByteCode Like.
Is there any documentation API that helps toward that.
The documentation says it is easy to generate the ByteCode but does not get in great details about the bytecode and its shapes and so on.
I am hoping that someone could help with that: the section Graph Language Provider is empty in the current documentation
On the JVM you can get a Bytecode object from any traversal with asAdmin().getBytecode() as follows:
gremlin> g.V().hasLabel('person').out().in().tree().asAdmin().getBytecode()
==>[[], [V(), hasLabel(person), out(), in(), tree()]]
Converted to GraphSON format the Bytecode format looks like this (example from the IO documentation):
{
"#type" : "g:Bytecode",
"#value" : {
"step" : [ [ "V" ], [ "hasLabel", "person" ], [ "out" ], [ "in" ], [ "tree" ] ]
}
}
The full instruction set is basically bound to the JVM at this time and is simply the list of Gremlin steps plus related expressions/tokens (e.g. P, T, etc). We are currently working on getting Gremlin defined more as a specification first rather than having it bound to the JVM as it is today, but that will take some time to complete.
Note that you are talking about development of a Gremlin Compiler. There already is an example which is just about ready for release as I write this in sparql-gremlin - pre-release documentation can be found here. This module takes the SPARQL query language and converts it to Gremlin Bytecode.
gremlin> graph = TinkerFactory.createModern()
==>tinkergraph[vertices:6 edges:6]
gremlin> g = graph.traversal(SparqlTraversalSource) //1\
==>sparqltraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> g.sparql("""SELECT ?name ?age
WHERE { ?person v:name ?name . ?person v:age ?age }
ORDER BY ASC(?age)""") //2\
==>[name:vadas,age:27]
==>[name:marko,age:29]
==>[name:josh,age:32]
==>[name:peter,age:35]
The code is not terribly complex - perhaps you could look to it for inspiration. If you have further questions please consider asking them on gremlin-users mailing list. It would be great to see more Gremlin Compilers available. There are currently others (SQL and Cypher), but I believe that the SPARQL compiler is the only one that is Bytecode based at this time.

Have Gremlin-console show all the methods available for a specific object?

In gremlin-console, is there a way to show all the methods available for a specific object?
For example, In gremlin-console if I type g.V().hasLabel("person") and I want to see what methods I can chain/call for the object returned by g.V().hasLabel("person"). How do you do that?
The answer is to use the <Tab> key.
gremlin> "test".c
capitalize() center( charAt( chars() codePointAt( codePointBefore( codePointCount( codePoints() collectReplacements( compareTo(
compareToIgnoreCase( concat( contains( contentEquals( count(
However, I'm finding that it is not working for something like g.V().o which I'd hoped would have shown out(). Apparently, the groovy shell (which is what the Gremlin Console is based on) doesn't seem to want to do the auto-complete on a fluent API. It seems to only work on the first object on which you are calling the method:
gremlin> g.
E( V( addV( addV() close() inject( tx() withBindings( withBulk(
withComputer( withComputer() withPath() withRemote( withSack( withSideEffect( withStrategies( withoutStrategies( anonymousTraversalClass
bytecode graph strategies
gremlin> x = g.V();[]
gremlin> x.o
option( optional( or( order( order() otherV() out( outE( outV()
gremlin> x.o
That stinks...that's not really a TinkerPop issue - we rely on the groovysh for that functionality. Not much we can do there I don't think....
Of course, you are using DSE Graph which means you have access to DataStax Studio which not only has the auto-complete that you're looking for but also schema support (and more!). I'd suggest that you switch to that.

Paging or Using Skip in Azure Cosmos

Has anyone been able to determine the equivalent of Gremlin Skip in Azure Cosmos? It's not listed on Microsoft's documentation and I was thinking it's just outdated. I did try doing a query such as g.V().hasLabel('the_label').has('the_property', eq('the_value')).skip(some_number) and it errors out as such Unable to find any method 'skip'.
From your link in the Apache TinkerPop documentation:
The skip()-step is analogous to range()-step save that the higher end range is set to -1.
with these examples:
gremlin> g.V().values('age').order().skip(2)
==>32
==>35
gremlin> g.V().values('age').order().range(2, -1)
==>32
==>35

Can't update HashMap in Titan created via RexPro

I'm running Titan 0.3.2 with Cassandra as a data store. I'm also using rexpro-python for interacting with Titan over RexPro.
Issue & Question:
If I run this Python code:
>>> import rexpro
>>> conn = rexpro.RexProConnection('localhost', 8184, 'graph')
>>> conn.execute('g.addVertex(null, node_dict)', {'node_dict':{'my_dict':{}}})
{'_type': 'vertex', '_id': '2280164', '_properties': {'my_dict': {}}}
>>> conn.execute('g.commit()')
I can look up the resulting node in the Gremlin console:
gremlin> g.v(2280164).map
==>{my_dict={}}
And it looks like the my_dict map is created properly:
gremlin> g.v(2280164).my_dict.getClass()
==>class java.util.HashMap
However, I'm unable to update my_dict with a new key & value:
gremlin> g.v(2280164).my_dict['abc'] = 123
==>123
gremlin> g.commit()
==>null
gremlin> g.v(2280164).map
==>{my_dict={}}
If I first reset my_dict to a new object in the console, my attempt to add key abc works as expected:
gremlin> g.v(2280164).my_dict = [:]
gremlin> g.v(2280164).my_dict['abc'] = 123
==>123
gremlin> g.v(2280164).map
==>{my_dict={abc=123}}
My question: how can I update my_dict with a new KV pair on a vertex created via RexPro?
Attempted workarounds/solutions:
This same issue happens when the vertex is created with a non-parameterized version of the python script:
>>> conn.execute('g.addVertex([my_dict:[:]])')
Also, not sure if relevant for this issue, but it looks like the new map created in the console is a LinkedHashMap (whereas the python/rexpro code created a HashMap):
gremlin> g.v(2280164).my_dict.getClass()
==>class java.util.LinkedHashMap
Updating the dictionary/map that comes off a vertex property circumvents the database level since you are directly modifying the value on the heap.
In other words, Titan does not know that you updated the map and therefore does not persist the change.
Always think of property values as immutable even though they might be mutable java objects because those mutations are invisible to the database.
This will work:
newdict = v.my_dict.clone()
newdict['hello']='other'
v.setProperty('my_dict',newdict)
graph.commit()
v.map
I tried to recreate this entirely in the REPL and couldn't. I even explicitly created a java.util.HashMap and it seemed to work fine with Titan/Cassandra. I think LinkedHashMap is the default for groovy when you do [:].
gremlin> g = TitanFactory.open('bin/cassandra.local')
==>titangraph[cassandrathrift:127.0.0.1]
gremlin> g.addVertex()
==>v[4]
gremlin> g.v(4).my_dict = new java.util.HashMap()
gremlin> g.v(4).map
==>{my_dict={}}
gremlin> g.v(4).my_dict['abc'] = 123
==>123
gremlin> g.v(4).map
==>{my_dict={abc=123}}
gremlin> g.v(4).my_dict.getClass()
==>class java.util.HashMap
gremlin> g.commit()
==>null
gremlin> g.v(4).map
==>{my_dict={abc=123}}
What happens if you don't parameterize your RexPro request? In other words, do you get different results if you do:
>>> conn.execute('g.addVertex([my_dict:[:]])')
If that works that might be a workaround for you. I know the recommendation is to "parameterize requests" via RexPro but since this script is basically static, it will cache nicely in the scriptengine at not much additional cost per request.

Resources