Reputation: 487
The query should to the following:
The following works if traversal
is a pristine traversal.
If traversal
already contains some other steps (e.g. creation of a vertex)
it crashes with below error.
properties = {"p1": "p1_value", "p2": "p2_value"}
traversal.V().inject(properties).as_(props_label).
V().has("uuid",from_uuid).as_(from_label).
V().has("uuid",to_uuid).as_(to_label).
coalesce(inE(edge_label).where(outV().
as_(from_label)),addE(edge_label).
from_(from_label).as_(e_label).select(props_label).
unfold().as_(kv_label).select(e_label).
property(select(kv_label).by(Column.keys),select(kv_label).by(Column.values))).iterate()
gremlin_python.driver.protocol.GremlinServerError: 500: The provided object does not have accessible keys: class org.janusgraph.graphdb.vertices.StandardVertex
If I iterate()
the traversal before injecting
, it works. But I would like to avoid the iterate for performance reasons.
Any ideas?
edit:
I did some more testing. Adding the vertices beforehand works. Adding them in the same query does not.
This works:
gremlin> g.addV("TestType").property("name", "1")
==>v[2302192]
gremlin> g.addV("TestType").property("name", "2")
==>v[2326704]
gremlin> g.inject(["p1": "v1", "p2": "v2"]).unfold().as("props").V(2302192).as("from").V(2326704).as("to").coalesce(inE("DEPENDS_ON").where(outV().as("from")), addE("DEPENDS_ON").from("from").property(select("props").by(keys), select("props").by(values)))
==>e[187by-1dcds-1lh-1dvao][2302192-DEPENDS_ON->2326704]
==>e[187by-1dcds-1lh-1dvao][2302192-DEPENDS_ON->2326704]
This fails:
gremlin> g.addV("TestType").property("name", "1").addV("TestType").property("name", "2").inject(["p1": "v1", "p2": "v2"]).unfold().as("props").V().has("name", "1").as("from").V().has("name", "2").as("to").coalesce(inE("DEPENDS_ON").where(outV().as("from")), addE("DEPENDS_ON").from("from").property(select("props").by(keys), select("props").by(values))).dedup()
The provided object does not have accessible keys: class org.janusgraph.graphdb.vertices.StandardVertex
Upvotes: 1
Views: 1263
Reputation: 487
Just for reference for anybody who might stumble upon this in the future. I found a solution that is much simpler using an anonymous traversal instead of injection:
properties = {"some key": "some value", "etc": "bla"}
# prepare the add vertex sub traversal
add_vertex_traversal = addV(label)
for k, v in properties.items():
add_vertex_traversal = add_vertex_traversal.property(k, v)
g.V().has('some_prop', "some_value").fold().coalesce(unfold(),add_vertex_traversal))
Upvotes: 2
Reputation: 46226
As an initial point, you do not need the first V
in your traversal. You just need to start with inject()
. If you start with V()
you end up executing the following steps for every vertex in the graph.
That said, I don't see a problem with your traversal and it works fine with TinkerGraph once I adapted it to the modern toy graph:
gremlin> g = TinkerFactory.createModern().traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> properties = [p1: "p1_value", p2: "p2_value"]
==>p1=p1_value
==>p2=p2_value
gremlin> g.inject(properties).as('props_label').
......1> V().has("name",'marko').as('from_label').
......2> V().has("name",'josh').as('to_label').
......3> coalesce(inE('knows').where(outV().as('from_label')),
......4> addE('knows').from('from_label').as('e_label').select('props_label').
......5> unfold().as('kv_label').select('e_label').
......6> property(select('kv_label').by(Column.keys),
......7> select('kv_label').by(Column.values)))
==>e[8][1-knows->4]
gremlin> g.inject(properties).as('props_label').
......1> V().has("name",'peter').as('from_label').
......2> V().has("name",'vadas').as('to_label').
......3> coalesce(inE('knows').where(outV().as('from_label')),
......4> addE('knows').from('from_label').as('e_label').select('props_label').
......5> unfold().as('kv_label').select('e_label').
......6> property(select('kv_label').by(Column.keys),
......7> select('kv_label').by(Column.values)))
==>e[13][6-knows->2]
==>e[13][6-knows->2]
You may wish to dedup()
results on this traversal as you will get one result for each property key in the map given its unfold()
at line 5.
The error you're getting is a server-side error and I don't think an issue with gremlinpython. It points to a situation where select('kv_label').by(Column.keys)
is trying to access a JanusGraph StandardVertex
object. I can recreate that problem in TinkerGraph easily enough given your updated question:
gremlin> g.addV("TestType").property("name", "1").
......1> addV("TestType").property("name", "2").
......2> inject(["p1": "v1", "p2": "v2"]).
......3> unfold().as("props").
......4> V().has("name", "1").as("from").
......5> V().has("name", "2").as("to").
......6> coalesce(inE("DEPENDS_ON").where(outV().as("from")),
......7> addE("DEPENDS_ON").from("from").
......8> property(select("props").by(keys), select("props").by(values))).dedup()
The provided object does not have accessible keys: class org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerVertex
Type ':help' or ':h' for help.
Display stack trace? [yN]n
This is a very different traversal from your original question which is why I wasn't able to recreate it. You're expecting just key/value pairs from your inject()
in the stream but it in fact has something else:
gremlin> g.addV("TestType").property("name", "1").
......1> addV("TestType").property("name", "2").
......2> inject(["p1": "v1", "p2": "v2"]).
......3> unfold()
==>p1=v1
==>p2=v2
==>v[2]
When v[2]
makes its way to select("props").by(keys)
you get the exception I described. You can fix it by moving inject()
to the start or using withSideEffect()
gremlin> g.inject(["p1": "v1", "p2": "v2"]).as('props').
......1> addV("TestType").property("name", "1").
......2> addV("TestType").property("name", "2").
......3> V().has("name", "1").as("from").
......4> V().has("name", "2").as("to").
......5> coalesce(inE("DEPENDS_ON").where(outV().as("from")),
......6> addE("DEPENDS_ON").from("from").as('e').
......7> select('props').
......8> unfold().as('kv').
......9> select('e').
.....10> property(select("kv").by(keys), select("kv").by(values))).dedup()
==>e[4][0-DEPENDS_ON->2]
gremlin> g.withSideEffect('props', ["p1": "v1", "p2": "v2"]).
......1> addV("TestType").property("name", "1").
......2> addV("TestType").property("name", "2").
......3> V().has("name", "1").as("from").
......4> V().has("name", "2").as("to").
......5> coalesce(inE("DEPENDS_ON").where(outV().as("from")),
......6> addE("DEPENDS_ON").from("from").as('e').
......7> select('props').
......8> unfold().as('kv').
......9> select('e').
.....10> property(select("kv").by(keys), select("kv").by(values))).dedup()
==>e[4][0-DEPENDS_ON->2]
I'm not sure which is more intuitive. I tend to prefer inject()
when I need something to start the traversal, but you have addV()
to put objects in the start, so inject()
seems clumsy there especially since addV()
just replaces the Map
its given. In this case, I think using withSideEffect()
more explicitly tells someone reading this what the intent is.
Upvotes: 2