TinkerPop3 Gremlin traversal - gremlin

First, Given a Node A, first we need to find out all nodes that could be reached through the "Friend" edges(A,B,C... all the blue nodes). I can achieve this by using the path()-step like bellow:
g.V().hasLabel("Person").has("name", "A")
.repeat(out("Friend"))
.until(out("Friend").count().is(0))
.path();
And then we can extract verticals from the path objects in java code.
But actually, we need to find out what books they read(the green ones). But we can't extract the verticals from path() in gremlin.
Is there any way we could do this in one gremlin traversal?
Edit:
In fact, there is 2 situations:
from A, find out all persons connected through "Friend" edge. We did this by the traversal mentioned above. (is there any better way? ie. extract these nodes directly in gremlin?)
from A, find out all persons then all books they read, and return the books, only the books.

You could use the union step.
g.V()
.hasLabel("person")
.has("name", "A")
.repeat(union(out("friend"),
out("read")))
.until(out("friend").count().is(0))
.union(path(),
out("read").path())
Should get you what you need. With a graph defined as
gremlin> :> graph.addVertex(T.label, "person", "name", "A")
==>v[0]
gremlin> :> graph.addVertex(T.label, "person", "name", "B")
==>v[2]
gremlin> :> graph.addVertex(T.label, "person", "name", "C")
==>v[4]
gremlin> :> graph.addVertex(T.label, "person", "name", "D")
==>v[6]
gremlin> :> a = g.V(0).next(); b = g.V(2).next(); a.addEdge("friend", b, "is", "is");
==>e[8][0-friend->2]
gremlin> :> b = g.V(2).next(); c = g.V(4).next(); a.addEdge("friend", b, "is", "is");
==>e[9][2-friend->4]
gremlin> :> a = g.V(0).next(); d = g.V(6).next(); a.addEdge("friend", b, "is", "is");
==>e[10][0-friend->6]
gremlin> :> graph.addVertex(T.label, "book", "name", "Huck Finn")
==>v[11]
gremlin> :> graph.addVertex(T.label, "book", "name", "Tom Sawyer")
==>v[13]
gremlin> :> graph.addVertex(T.label, "book", "name", "A Tale Of Two Cities")
==>v[15]
gremlin> :> a = g.V(0).next(); b = g.V(11).next(); a.addEdge("read", b, "is", "is");
==>e[17][0-read->11]
gremlin> :> a = g.V(2).next(); b = g.V(13).next(); a.addEdge("read", b, "is", "is");
==>e[18][2-read->13]
gremlin> :> a = g.V(4).next(); b = g.V(15).next(); a.addEdge("read", b, "is", "is");
==>e[19][4-read->15]
It yields
gremlin> :> g.V().hasLabel("person").has("name", "A").repeat(union(out("friend"), out("read"))).until(out("friend").count().is(0)).union(path(), out("read").path())
==>[v[0], v[6]]
==>[v[0], v[11]]
==>[v[0], v[2], v[4]]
==>[v[0], v[2], v[4], v[15]]
==>[v[0], v[2], v[13]]

Related

how can we get 2 vertexes path?

Now I have the query below and I would like to get all the edge and It is interesting why we got 2 same path and I want to get the path detail. How can I implement?
Vertex fromNode = g.V().has('name', 'alice').next();Vertex toNode = g.V().has('name', 'bobby').next();g.V(fromNode).repeat(both().simplePath()).until(is(toNode)).path()
==>[v[4224],v[40964296]]
==>[v[4224],v[40964296]]
==>[v[4224],v[4144],v[40964256],v[4096],v[40964296]]
We have the Graph below.
gremlin> a = graph.addVertex("name", "alice")
==>v[4208]
gremlin> b = graph.addVertex("name", "bobby")
==>v[40968424]
gremlin> c = graph.addVertex("name", "cindy")
==>v[4192]
gremlin> d = graph.addVertex("name", "david")
==>v[40972520]
gremlin> e = graph.addVertex("name", "eliza")
==>v[40964272]
gremlin> a.addEdge("rates",b,"tag","ruby","value",9)
==>e[2ry-38w-azv9-oe3fs][4208-rates->40968424]
gremlin> b.addEdge("rates",c,"tag","ruby","value",8)
==>e[odzq5-oe3fs-azv9-38g][40968424-rates->4192]
gremlin> c.addEdge("rates",d,"tag","ruby","value",7)
==>e[170-38g-azv9-oe6lk][4192-rates->40972520]
gremlin> d.addEdge("rates",e,"tag","ruby","value",6)
==>e[oe04d-oe6lk-azv9-oe08g][40972520-rates->40964272]
gremlin> a.addEdge("rates",e,"tag","java","value",9)
==>e[366-38w-azv9-oe08g][4208-rates->40964272]
gremlin> g.E().values("tag")
==>ruby
==>ruby
==>ruby
==>ruby
==>java
gremlin> graph.tx().commit()
I would like to get the path detail like below:
==>bobby=[v[0], e[10][0-rates->2], v[2]]
==>cindy=[v[0], e[10][0-rates->2], v[2], e[11][2-rates->4], v[4]]
==>david=[v[0], e[10][0-rates->2], v[2], e[11][2-rates->4], v[4], e[12][4-rates->6], v[6]]
You just need to specify that you want the edges as well by traversing over them explicitly:
gremlin> g.V(fromNode).repeat(bothE().otherV().simplePath()).until(is(toNode)).path()
==>[v[0],e[10][0-rates->2],v[2]]
==>[v[0],e[14][0-rates->8],v[8],e[13][6-rates->8],v[6],e[12][4-rates->6],v[4],e[11][2-rates->4],v[2]]

how to add a vertex only if it doesn't exist and continue this single traversal with other graph mutations?

Currently I have this gremlin/groovy code:
if(!g.V().has("Number","number","3").hasNext()) {
g.addV("Number").property("number","3")
}
Is it possible to have the same result without using multiple traversals?
I tried this and it doesn't work (it doesn't add either Number or User vertices)
g.V().choose(has("Number","number", "3"),
addV("Number").property("number", "3"),
has("Number","number", "3")
).as("number")
.addV("User").property("uuid","test uuuid")
.forEachRemaining(System.out::println);
I tried what it was suggested here (https://stackoverflow.com/a/33965737/986160) but it doesn't allow me to continue my single traversal with adding another user in a single transaction for DSE:
g.V()
.has("Number","number", "3")
.tryNext()
.orElseGet(
() -> g.addV("Number")
.property("number", "3").next()
);
Thanks!
Unfortunately we don't have g.coalesce() yet, but there's a workaround:
gremlin> g = TinkerGraph.open().traversal()
==>graphtraversalsource[tinkergraph[vertices:0 edges:0], standard]
gremlin> g.inject(1).coalesce(V().has("Number", "number", 3), addV("Number").property("number", 3))
==>v[0]
gremlin> g.inject(1).coalesce(V().has("Number", "number", 3), addV("Number").property("number", 3))
==>v[0]
gremlin> g.inject(1).coalesce(V().has("Number", "number", 3), addV("Number").property("number", 3))
==>v[0]
gremlin> g.V().valueMap()
==>[number:[3]]

TinkerPop 3: Gremlin query to group count by edge direction

I have a vertex id to start with and wanted to get counts of in and out edges.
g.traversal().V().has("__id", "1234").groupCount().by(Direction.BOTH)
As .by() step wont accept Direction type., is there any alternative way?
You can do this nicely with project step:
gremlin> graph = TinkerFactory.createModern()
==>tinkergraph[vertices:6 edges:6]
gremlin> g = graph.traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> g.V().has('name','marko').
project('out','in').
by(outE().count()).
by(inE().count())
==>[out:3,in:0]
For TinkerPop 3.0.x, which didn't have project you could do:
gremlin> g.V().has('name','marko').as('out','in').
select('out','in').
by(outE().count()).
by(inE().count())
==>[out:3,in:0]

How do I write Gremlin queries for following patterns?

I have some miniature Gremlin directed graphs, in which each vertex has two properties "type" and "text". The values for "text" property are just English text while the "type" property can a have a value selected from this set :
NP, PP, VP, ADVP, ADJP, SBAR, PRT, INTJ, O
All edges in those graphs have same label : "next".
I want to be able to select the graphs which have following patterns of nodes:
1) [text=","] --> type="VP" --> type="ADVP" --> type="NP"
2) type="NP" --> [text="," Upto 3 nodes with any text and type text=","] --> type="VP" --> [text=":" OR "that"]
The pattern element in brackets means that it is optional.
So, for first pattern, I need to select the graphs which have a node with text "," optionally, followed by a node with type "VP", followed by "ADVP", followed "NP".
For second pattern, I need to select the graphs which have a node type "NP", followed by an optional sequence of nodes starting with a node with text "," then upto 3 nodes with any text and type and then a node with text ",". This optional sequence is then followed by a node of type "VP" and finally a node with text ":" or "that".
Two sample graphs that would match with first pattern are :
Following are sample graphs that would match with second pattern:
I understand basic Gremlin traversals but I am not sure about how to handle optional elements of the pattern above.
Is there any way to write queries for such patterns in Gremlin? If not, can you suggest a non-Gremlin based approach to create such graphs and querying them ?
You can do pattern matching in Gremlin as of TinkerPop 3.0. You would use Match Step to accomplish your task. I've written the Gremlin to do so as an example for your first requirement. Perhaps that will inspire you to develop the traversal for your second requirement.
I generated some data as follows:
gremlin> graph = TinkerGraph.open()
==>tinkergraph[vertices:0 edges:0]
gremlin> g = graph.traversal()
==>graphtraversalsource[tinkergraph[vertices:0 edges:0], standard]
gremlin> v1=g.addV(id, 1, "type", "o", "text", ",").next()
==>v[1]
gremlin> v2=g.withSideEffect('x',v1).addV(id, 2, "type", "vp", "text", "a").addInE('next','x').inV().next()
==>v[2]
gremlin> v3=g.withSideEffect('x',v2).addV(id, 3, "type", "advp", "text", "b").addInE('next','x').inV().next()
==>v[3]
gremlin> g.withSideEffect('x',v3).addV(id, 4, "type", "np", "text", "c").addInE('next','x').inV().next()
==>v[4]
gremlin>
gremlin> v5=g.addV(id, 5, "type", "vp", "text", "a").next()
==>v[5]
gremlin> v6=g.withSideEffect('x',v5).addV(id, 6, "type", "advp", "text", "b").addInE('next','x').inV().next()
==>v[6]
gremlin> g.withSideEffect('x',v6).addV(id, 7, "type", "np", "text", "c").addInE('next','x').inV().next()
==>v[7]
gremlin>
gremlin> v8=g.addV(id, 8, "type", "vp", "text", "a").next()
==>v[8]
gremlin> v9=g.withSideEffect('x',v8).addV(id, 9, "type", "o", "text", ",").addInE('next','x').inV().next()
==>v[9]
gremlin> g.withSideEffect('x',v9).addV(id, 10, "type", "np", "text", "c").addInE('next','x').inV().next()
==>v[10]
Then for the matching traversal:
gremlin> g.V().has('type','vp').match(__.as('vp').coalesce(__().in().has('text',','),constant("optional")).as('o'),
gremlin> __.as('vp').out().has('type','advp').as('advp'),
gremlin> __.as('advp').out().has('type','np').as('np')).select('o','vp','advp','np')
==>[o:v[1], vp:v[2], advp:v[3], np:v[4]]
==>[o:optional, vp:v[5], advp:v[6], np:v[7]]

find all paths between 2 vertices by only considering vertex where propertyname = value

I am having a a traversal use case as follows .Does orientDb supports it?
1)Find all paths from node1 to node2 .ONLY TRAVERSE those nodes which has property xyz="val1"
2)Find shortest path .ONLY TRAVERSE those nodes which has property xyz="val1"
3)Find longest path .ONLY TRAVERSE those nodes which has property xyz="val1"
abstract class TraversGraph{
public Path getPath(Node src,Node dest, Propery property,Value value);
}
Note :Please note the condition which i mentioned in caps
You can use Gremlin to get paths between two nodes. You can firstly find all the paths, so the shortest and the longest are included in all these paths.
Here is an example:
As you can see in the image, from A to B there are three paths(A->B, A->F->C->B, A->E->D->C->B), but node F doesn't have property "xyz" with value "val1", so this paths should not be included.
Code:
gremlin> g = new TinkerGraph()
==>tinkergraph[vertices:0 edges:0]
gremlin> a = g.addVertex(null,[name: "A", xyz: "val1"])
==>v[0]
gremlin> b = g.addVertex(null,[name: "B", xyz: "val1"])
==>v[1]
gremlin> c = g.addVertex(null,[name: "C", xyz: "val1"])
==>v[2]
gremlin> d = g.addVertex(null,[name: "D", xyz: "val1"])
==>v[3]
gremlin> e = g.addVertex(null,[name: "E", xyz: "val1"])
==>v[4]
gremlin> f = g.addVertex(null,[name: "F"])
==>v[5]
gremlin> g.addEdge(a, b, "KNOWS")
==>e[6][0-KNOWS->1]
gremlin> g.addEdge(a, e, "KNOWS")
==>e[7][0-KNOWS->4]
gremlin> g.addEdge(a, f, "KNOWS")
==>e[8][0-KNOWS->5]
gremlin> g.addEdge(f, c, "KNOWS")
==>e[9][5-KNOWS->2]
gremlin> g.addEdge(e, d, "KNOWS")
==>e[10][4-KNOWS->3]
gremlin> g.addEdge(d, c, "KNOWS")
==>e[11][3-KNOWS->2]
gremlin> g.addEdge(c, b, "KNOWS")
==>e[12][2-KNOWS->1]
And traversel between node A and node B(Here we do not filter the property "xyz"), so we get three paths:
gremlin> a.out('KNOWS').loop(1){it.loops<100}{true}.has('name', 'B').path{it.name}
==>[A, B]
==>[A, F, C, B]
==>[A, E, D, C, B]
And add the filter of property "xyz"
gremlin> a.out('KNOWS').loop(1){it.loops<100 && it.object.hasNot('xyz', null)}{true}.has('name', 'B').path{it.name}
==>[A, B]
==>[A, E, D, C, B]
Thus we get the shortest path: [A, B]
and the longest path: [A, E, D, C, B]
English is not my mother language, so if any confusion, feel free to contact me.

Resources