Python/Neptune/Gremlin: "'list' object has no attribute 'next'" - gremlin

I trying to mirror the following gremlin code in Python to do pagination.
gremlin> t = g.V().hasLabel('person');[]
gremlin> t.next(2)
==>v[1]
==>v[2]
gremlin> t.next(2)
==>v[4]
==>v[6]
Here are the Python code
from neptune_python_utils.gremlin_utils import GremlinUtils
from neptune_python_utils.endpoints import Endpoints
GremlinUtils.init_statics(globals())
endpoints = '...'
gremlin_utils = GremlinUtils(endpoints)
conn = gremlin_utils.remote_connection()
g = gremlin_utils.traversal_source(connection=conn)
t = g.V().hasLabel('my-label')
cnt, ipp = True, 100
while cnt:
r = t.next(ipp)
if not r:
cnt = False
But I'm getting error
"errorMessage": "'list' object has no attribute 'next'",
"errorType": "AttributeError"
on line ---> r = t.next(ipp)
The trace show that the first iteration for r = t.next(ipp) actually ran, but it returned a list object, so there is no .next()
anymore. How can I keep the traversal in the iterations?

Related

Gremlin CSV parse creating extra vertices

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]

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]]

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]]

How do you find all vertices that have no incoming edges?

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.

Add edge between existing nodes in Gremlin

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.

Resources