I'm new to Gremlin and just trying to build out a basic graph. I've been able to do a basic addEdge on new vertices, i.e.
gremlin> v1 = g.addVertex()
==>v[200004]
gremlin> v2 = g.addVertex()
==>v[200008]
gremlin> e = g.addEdge(v1, v2, 'edge label')
==>e[4c9f-Q1S-2F0LaTPQN8][200004-edge label->200008]
I have also been able to create an edge between vertices looked up by id:
gremlin> v1 = g.v(200004)
==>v[200004]
gremlin> v2 = g.v(200008)
==>v[200008]
gremlin> e = g.addEdge(v1, v2, 'edge label')
==>e[4c9f-Q1S-2F0LaTPQN8][200004-edge label->200008]
However, I now want to look up vertices based on multiple properties, which is where it gets tricky. In order to look up the right vertex, I'm making 2 calls to .has. It appears that the correct vertices are found, but adding the edge fails.
gremlin> v1 = g.V.has("x",5).has('y",7)
==>v[200004]
gremlin> v2 = g.V.has("x",3).has('y",5)
==>v[200008]
gremlin> e = g.addEdge(v1, v2, 'edge label')
No signature of method: groovy.lang.MissingMethodException.addEdge() is applicable for argument types: () values: []
What's the easiest way to add a simple edge between two existing vertices, based on a property value lookup?
The key issue is that .has returns a Pipe: in order to get the specific vertex instance, a simple call to .next() does the trick:
gremlin> v1 = g.V.has("x",5).has('y",7).next()
==>v[200004]
gremlin> v2 = g.V.has("x",3).has('y",5).next()
==>v[200008]
gremlin> e = g.addEdge(v1, v2, 'edge label')
==>e[4c9f-Q1S-2F0LaTPQN8][200004-edge label->200008]
Note that .next() will simply return the next item in the pipe. In this case, any additional vertices matching the property values are ignored.
Related
I am just Two days in to gremlin. I have set of vertices and colored edges. I want to find path from S2 to D2. If I enter to black vertex through green edge ( G1 -B1) then I have to come out only through green edge (B2-G2) . I should n't come out of red edge.
Below query works, But I can’t hardcode colors (has('color',within("green") in 3rd line).
g.V().hasLabel("S2").repeat(outE("tx").choose(values("type")).
option("multiplex",aggregate(local,"colors").by("color").inV()).
option("demultiplex",has('color',within("green")).inV()).
option(none,__.inV()).
simplePath()).until(hasLabel("D2")).path().by(label())
So I tried below query It doesn’t give any path. If my edge has label “multiplex” then I store the color . If my edge has label “demultiplex” then I read the color from store.
g.V().hasLabel("S2").repeat(outE("tx").choose(values("type")).
option("multiplex",aggregate("colors").by("color").inV()).
option("demultiplex",has("color",within(select("colors").unfold())).inV()).
option(none,__.inV()).
simplePath()).until(hasLabel("D2")).path().by(label())
Below code populates the graph
Vertex s1 = g.addV("S1").next();
Vertex s2 = g.addV("S2").next();
Vertex d1 = g.addV("D1").next();
Vertex d2 = g.addV("D2").next();
Vertex r1 = g.addV("R1").next();
Vertex r2 = g.addV("R2").next();
Vertex r3 = g.addV("R3").next();
Vertex r4 = g.addV("R4").next();
Vertex g1 = g.addV("G1").next();
Vertex g2 = g.addV("G2").next();
Vertex g3 = g.addV("G3").next();
Vertex g4 = g.addV("G4").next();
Vertex b1 = g.addV("B1").next();
Vertex b2 = g.addV("B2").next();
Vertex b3 = g.addV("B3").next();
Vertex b4 = g.addV("B4").next();
g.V(s1).addE("tx").to(r1).property("type","straight").next();
g.V(r1).addE("tx").to(b1).property("color","red").property("type","multiplex").next();
g.V(s2).addE("tx").to(g1).property("type","straight").next();
g.V(g1).addE("tx").to(b1).property("color","green").property("type","multiplex").next();
g.V(b1).addE("tx").to(b2).property("type","straight").next();
g.V(b2).addE("tx").to(r2).property("color","red").property("type","demultiplex").next();
g.V(b2).addE("tx").to(g2).property("color","green").property("type","demultiplex").next();
g.V(r2).addE("tx").to(r3).property("type","straight").next();
g.V(g2).addE("tx").to(g3).property("type","straight").next();
g.V(r3).addE("tx").to(b3).property("color","red").property("type","multiplex").next();
g.V(g3).addE("tx").to(b3).property("color","green").property("type","multiplex").next();
g.V(b3).addE("tx").to(b4).property("type","straight").next();
g.V(b4).addE("tx").to(g4).property("color","green").property("type","demultiplex").next();
g.V(g4).addE("tx").to(d2).property("type","straight").next();
g.V(b4).addE("tx").to(r4).property("color","red").property("type","demultiplex").next();
g.V(r4).addE("tx").to(d1).property("type","straight").next();
You were pretty close. This syntax is always tempting:
has("color",within(select("colors").unfold())
but it doesn't work that way as you've found. That P syntax doesn't take a Traversal that way. You need to use a form of where() when you need to reference a side-effect (i.e. "colors").
gremlin> g.V().hasLabel("S2").
......1> repeat(outE("tx").
......2> choose(values("type")).
......3> option("multiplex",aggregate(local,"colors").by("color").inV()).
......4> option("demultiplex", filter(values('color').as('c').
......5> where('c',eq('colors')).
......6> by().
......7> by(unfold().tail())).inV()).
......8> option(none,__.inV()).
......9> simplePath()).
.....10> until(hasLabel("D2")).
.....11> path().by(label)
==>[S2,tx,G1,tx,B1,tx,B2,tx,G2,tx,G3,tx,B3,tx,B4,tx,G4,tx,D2]
My code should read the 4 columns, split them into vertices for the first 2 columns, and edge properties for the last two columns.The CSV file has 33 unique vertices in 37 lines of data. What I don't understand is why I get 74 vertices instead and 37 edges. Interestingly enough, if I omit the addE statment I just get 37 vertices.
Obviously the property portion hasn't been included as I've been trying to resolve my current issues.
1\t2\tstep\tcmp
2\t3\tconductor\tna
3\t4\tswitch\tZ300
\t for tab
etc.
My code is:
graph = TinkerGraph.open()
graph.createIndex('myId', Vertex.class)
g = graph.traversal()
getOrCreate = { myid ->
p = g.V('myId', myid)
if (!p.hasNext())
{g.addV('connector').property('myId',myid) }
else
{p.next()}
}
new File('Continuity.txt').eachLine {
if (!it.startsWith("#")){
def row = it .split('\t')
def fromVertex = getOrCreate(row[0])
def toVertex = getOrCreate(row[1])
g.addE("connection").from(fromVertex).to(toVertex).iterate()
}
}
There's at least on problem in the code that I see. In this line:
p = g.V('myId', myid)
you are telling gremlin to find vertices with ids "myId" and whatever the value of the variable myid is. You instead want:
p = g.V().has('myId', myid)
The syntax you were using is from TinkerPop 2.x. I tested your code this way with some other changes and it seems to work properly now:
gremlin> graph = TinkerGraph.open()
==>tinkergraph[vertices:0 edges:0]
gremlin> graph.createIndex('myId', Vertex.class)
gremlin> g = graph.traversal()
==>graphtraversalsource[tinkergraph[vertices:0 edges:0], standard]
gremlin> getOrCreate = { myid ->
......1> if (!g.V().has('myId', myid).hasNext())
......2> g.addV('connector').property('myId',myid)
......3> else
......4> g.V().has('myId', myid)
......5> }
==>groovysh_evaluate$_run_closure1#29d37757
gremlin> g.addE('connection').from(getOrCreate(1)).to(getOrCreate(2)).iterate()
gremlin> g.addE('connection').from(getOrCreate(1)).to(getOrCreate(2)).iterate()
gremlin> g.V()
==>v[0]
==>v[2]
gremlin> g.E()
==>e[4][2-connection->0]
==>e[5][2-connection->0]
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]]
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]]
Below I'm trying to find all vertices where there are no incoming edges using a filter on the vertices. fullyQualifiedName is a unique index. I noticed some vertices that appeared to have incoming edges so I added a step below to just print them out if they existed. I would have expected no output since I thought I had filtered these vertices above; however, I'm still seeing incoming edges displayed.
def g = BerkeleyGraphFactory.create()
def vertices = g.V.filter {
it.inE('depends').count() == 0
}
Set<String> u = []
u.addAll(vertices.collect {v->
v.fullyQualifiedName
})
u.each {
def focusIter = g.V('fullyQualifiedName', it)
def vertex = focusIter.next()
// this shouldn't print out anything since these vertices were filtered above
vertex.inE('depends').each { e->
def classRefV = e.outV.next()
println it + " is used by " + classRefV.name + " " + e.toString()
}
}
I can't seem to recreate your problem. A rough simplification of your code here seems to show that things work as expected:
gremlin> g = TinkerGraphFactory.createTinkerGraph()
==>tinkergraph[vertices:6 edges:6]
gremlin> ids = g.V.filter{!it.inE('knows').hasNext()}.id.toList()
==>1
==>3
==>5
==>6
gremlin> ids.collect{g.v(it).inE('knows').toList()}
==>[]
==>[]
==>[]
==>[]
Perhaps you can try to convert your code to match the approach I took to see if that helps? I'm not sure what else to say short of you providing some sample data to work with for your specific case where the problem can be recreated.