I'm using Java to access Gremlin. I have the following lines of code for creating a path between two vertices in an already created graph:
//begin simple path finding
Vertex fromNode = g.V().has("name", "i2").next();
Vertex toNode = g.V().has("name", "state1").next();
ArrayList list = new ArrayList();
g.V(fromNode).repeat(both().simplePath()).until(is(toNode)).limit(1).path().fill(list);
However, at this point I"m stuck. I can print out the list using list.toString() and I get the vertices that (I believe) are on the path. However, I now want to get those vertices themselves, access and potentially mutate their data. For instance, it isn't enough to know that v[32] is on the path if I can't access the ID 32 itself.
I should mention that I'm a bit new to this so please let me know if I'm using outdated/incorrect practices.
You ended up with a list filled with Path objects. I think what you're looking for is the unfold() step (see the docs) so you can unroll/flatten out the elements in path to put into the list. Here's a Gremlin Console session showing it:
gremlin> graph = TinkerGraph.open()
==>tinkergraph[vertices:0 edges:0]
gremlin> g = graph.traversal()
==>graphtraversalsource[tinkergraph[vertices:0 edges:0], standard]
gremlin> g.addV("name", "i2").as("a").addV("name", "state1").addE("to").from("a").toList()
==>e[4][0-to->2]
gremlin> fromNode = g.V().has("name", "i2").next()
==>v[0]
gremlin> toNode = g.V().has("name", "state1").next()
==>v[2]
gremlin> l = new ArrayList()
gremlin> g.V(fromNode).repeat(both().simplePath()).until(is(toNode)).limit(1).path().fill(l)
==>[v[0],v[2]]
gremlin> l = []; g.V(fromNode).repeat(both().simplePath()).until(is(toNode)).limit(1).path().fill(l)
==>[v[0],v[2]]
gremlin> l = []; g.V(fromNode).repeat(both().simplePath()).until(is(toNode)).limit(1).path().unfold().fill(l)
==>v[0]
==>v[2]
gremlin> l[0].getClass()
==>class org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerVertex
gremlin> l[0].property("name", "j3") // mutate the vertex's name
==>vp[name->i3]
gremlin> g.V(fromNode).valueMap(true).toList()
==>[id:0,name:[j3],label:vertex]
You should have access to these through list you're using on the fill step. The toString method won't print out the properties. If you just want to see those, you can call valueMap() instead of fill at the end of your traversal. If you'd like to iterate over all of the vertices and get the properties, you can use the properties method. If you want to get a specific property, you can use the property(key) method. The rest of what you'd need is in the API docs
Related
I have a graph with a single vertex:
gremlin> g.V().valueMap(true)
==>{id=a, x=[foo], label=vertex}
The vertex can be found in the following query:
gremlin> g.V().has('x', 'foo')
==>v[a]
However, I would like to modify the above query with the additional match constraint: match the vertex if it does not have property "y", or if the vertex does have property "y" and the value for property "y" equals "bar".
I have constructed the following query.
g.V().has('x', 'foo').or(__.hasNot('y'), __.has('y', 'bar'))
The query returns no matching vertices. So, I think I am looking for something equivalent to "IFNULL()" in mysql.
Any advice is much appreciated!
Joel
There's nothing wrong with your or() filter, it should just work.
gremlin> g = TinkerGraph.open().traversal()
==>graphtraversalsource[tinkergraph[vertices:0 edges:0], standard]
gremlin> g.addV().property(id, 'a').property('x', 'foo').iterate()
gremlin> g.V().has('x', 'foo').or(__.hasNot('y'), __.has('y', 'bar'))
==>v[a]
Alternatively you can check that there's no y value that is not bar.
gremlin> g.V().has('x', 'foo').not(__.values('y').is(neq('bar')))
==>v[a]
However, double negations tend to be confusing, so I would just go with or().
I'm trying basic JanusGraph operations on JVM.
When I attempt to simply create an edge between two vertices and calling vertex1.edges() I'm getting a result of org.janusgraph.graphdb.transaction.RelationConstructor rather Iterator<Edge>, which is against api.
I could regenerate the same result on Gremlin console once as shown below. But I'm getting proper org.janusgraph.graphdb.query.ResultSetIterator in my subsequent attempts.
gremlin> person = graph.addVertex(label, 'person')
==>v[163844144]
gremlin> graph.tx().commit()
==>null
gremlin> person2 = graph.addVertex(label, 'anotherperson')
==>v[245764240]
gremlin> person.addEdge("knows", person2);
==>e[2pjoxy-2pjqy8-29ed-42bkwg][163844144-knows->245764240]
gremlin> graph.tx().commit()
==>null
gremlin> person.class
==>class org.janusgraph.graphdb.vertices.StandardVertex
gremlin> mye = person.edges(Direction.BOTH, "knows")
==>e[2pjoxy-2pjqy8-29ed-42bkwg][163844144-knows->245764240]
gremlin> mye.class
==>class org.janusgraph.graphdb.transaction.RelationConstructor$1$1
Could someone please explain why and/or suggest a workaround?
Thank you!
You are getting back class org.janusgraph.graphdb.transaction.RelationConstructor$1$1. Take notice of the $1$1 which is indicating that you are dealing with an anonymous class within RelationConstructor. In particular, you are getting back this Iterator from the method readRelation(). To be sure, you could have called mye instanceof Iterator in your session to verify.
In this example below, I've added null to the end of the mye assignment to prevent the Gremlin Console auto-iteration behavior.
gremlin> mye = person.edges(Direction.BOTH, "knows"); null
==>null
gremlin> mye instanceof Iterator
==>true
gremlin> myedge = (mye.hasNext()) ? mye.next() : null
==>e[2pjoxy-2pjqy8-29ed-42bkwg][163844144-knows->245764240]
gremlin> myedge.class
==>class org.janusgraph.graphdb.relations.CacheEdge
I have a graph with the following structure:
|-ProductFit
|-|-Part
|-|-App
|-|-|-ProductID
|-|-|-ProductModelID
|-|-|-ProductYearID
|-ProductID
|-|-ProductName
|-|-ProductModelID
|-|-ProductYearID
|-ProductModelID
|-|-ProductModelName
|-ProductYearID
|-|-ProductYear
where ProductFit is my first independent vertex and ProductID, ProductModelID and ProductYearID as my connected vertices.
Now, there are some fields of ProductID's in ProductFit having wrong values for which I need to get values from other vertex of ProductID.
Here is my query:
g.V().has('ProductFit','Part','PA01').properties('App')
.valueMap('ProductID','ProductModelID','ProductYearID')
.choose(values('ProductModelID'))
.option(PM01, g.V().has('ProductFit','Part','PA01').properties('App').values('ProductModelID'))
.option(PM02, g.V().has('ProductID','ProductModelID','PM01'))
.values('ProductModelID')
But this is giving me this error:
java.util.HashMap cannot be cast to org.apache.tinkerpop.gremlin.structure.Element
Is it that I can't go from one vertex to other during traversal or is there some problem in query? TIA.
Your choose() is using values() which is not meant to pick values out of a Map. It is meant to be used with an Element. I get the same error on The Crew toy graph:
gremlin> graph = TinkerFactory.createTheCrew()
==>tinkergraph[vertices:6 edges:14]
gremlin> g = graph.traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:14], standard]
gremlin> g.V().properties('location').valueMap().choose(values('startTime')).option(2004,constant(1)).option(none,constant(2))
java.util.HashMap cannot be cast to org.apache.tinkerpop.gremlin.structure.Element
Type ':help' or ':h' for help.
Display stack trace? [yN]n
You should instead use select:
gremlin> g.V().properties('location').valueMap().choose(select('startTime')).option(2004,constant(1)).option(none,constant(2))
==>2
==>2
==>1
...
==>2
I'm trying to drop an edge and add a new edge between two vertices. How do I do that in Tinkerpop3?
def user = g.V().has("userId", 'iamuser42').has("tenantId", 'testtenant').hasLabel('User');
user.outE("is_invited_to_join").where(otherV().has("groupId", 'test123')).drop();
def group = g.V().has("groupId", 'test123').has("tenantId", 'testtenant').hasLabel('Group').next();
user.addEdge("is_member_of", group);
This is the error I get on gremlin shell:
No signature of method: org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal.addEdge() is applicable for argument types: (java.lang.String, com.thinkaurelius.titan.graphdb.vertices.CacheVertex) values: [is_member_of, v[8224]]
Thank you.
The Gremlin Console tutorial discusses this issue a bit. You are not iterating your traversal. Consider the following:
gremlin> graph = TinkerFactory.createModern()
==>tinkergraph[vertices:6 edges:6]
gremlin> g = graph.traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> person = g.V().has('name','marko')
==>v[1]
Great! The person Vertex is stored in the "person" variable...or is it?
gremlin> person.class
==>class org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal
Apparently it is not a Vertex. "person" is a Traversal, the console sees it as such and iterates it for you which is why you get "v1" in the output. Note that the traversal is now "done":
gremlin> person.hasNext()
==>false
You need to iterate the Traversal into your variable - in this case, using next():
gremlin> person = g.V().has('name','marko').next()
==>v[1]
gremlin> person.class
==>class org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerVertex
Note that you will have further problems down the line in your script because you are using what will now be a Vertex as a Traversal, so this line:
user.outE("is_invited_to_join").where(otherV().has("groupId", 'test123')).drop();
will now fail with a similar error because Vertex will not have outE(). You would need to do something like:
g.V(user).outE("is_invited_to_join").where(otherV().has("groupId", 'test123')).drop();
If you would like to add an edge and drop the old one in the same traversal, you could do something like this:
gremlin> graph = TinkerFactory.createModern()
==>tinkergraph[vertices:6 edges:6]
gremlin> g = graph.traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> g.V(1).outE('knows')
==>e[7][1-knows->2]
==>e[8][1-knows->4]
gremlin> g.V(1).as('a').outE().as('edge').inV().hasId(2).as('b').addE('knew').from('a').to('b').select('edge').drop()
gremlin> g.V(1).outE('knew')
==>e[12][1-knew->2]
gremlin> g.V(1).outE('knows')
==>e[8][1-knows->4]
Arguably, that might not be as readable as breaking it into two or more separate traversals, but it can be done.
Is there a way to return just a subset of all properties of a graph node with a Gremlin query?
I know you cand use the transform pipe to concatenate property values, but I'm more interested in obtaining structured results (like propertyName1 = value1, propertyName2 = value2).
Assuming you're using Gremlin-Groovy, I find using Groovy's each construct to be a useful way to create my own objects from Gremlin query results. For example:
nodes = []
g.V.each{ node ->
nodes += [ propertyName1 : node.value1, propertyName2 : node.value2 ]
}
Now you have a List of Map objects representing nodes returned from your query. It's possible this isn't the most efficient way but it is very flexible.
As of Gremlin 2.4.0, you can do:
gremlin> g = TinkerGraphFactory.createTinkerGraph()
==>tinkergraph[vertices:6 edges:6]
gremlin> g.v(1).out.map('name')
==>{name=vadas}
==>{name=josh}
==>{name=lop}
gremlin> g.v(1).out.map('name','age')
==>{age=27, name=vadas}
==>{age=32, name=josh}
==>{age=null, name=lop}
It is possible doing this:
If data is:
gremlin> g.E.has('weight', T.gt, 0.5f).outV.age
==>32
==>29
Then the query to do is:
gremlin> g.E.has('weight', T.gt, 0.5f).outV.transform{[id:it.id,age:it.age]}
==>{id=4, age=32}
==>{id=1, age=29}
Have you looked at using Table??
Sample from : Gremlin Wiki
gremlin> t = new Table()
gremlin> g.v(1).out('knows').as('x').out('created').as('y').table(t){it.name}{it.name}
==>v[5]
==>v[3]
gremlin> t
==>[x:josh, y:ripple]
==>[x:josh, y:lop]