Gremlin Python - 如果边不存在,则在创建边时向边添加未知数量的属性
Gremlin Python - Add unknown number of properties to edge on edge creation if edge does not exist
查询应该如下:
- 如果两个顶点之间存在边:return边
- else:创建边,根据字典设置属性,return 边。
如果 traversal
是原始遍历,则以下内容有效。
如果 traversal
已经包含一些其他步骤(例如创建顶点)
它因以下错误而崩溃。
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
如果我 iterate()
injecting
之前的遍历,它会起作用。但出于性能原因,我想避免迭代。
有什么想法吗?
编辑:
我做了更多测试。预先添加顶点是可行的。
将它们添加到同一个查询中不会。
这个有效:
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]
这失败了:
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
作为初始点,您不需要遍历中的第一个 V
。您只需要从 inject()
开始。如果您从 V()
开始,您最终会对图中的每个顶点执行以下步骤。
就是说,我没有发现您的遍历有问题,并且在我将它适应现代玩具图后,它与 TinkerGraph 一起工作得很好:
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]
您可能希望在此遍历中获得 dedup()
结果,因为在第 5 行给出其 unfold()
的情况下,地图中的每个 属性 键都会得到一个结果。
您收到的错误是服务器端错误,我认为 gremlinpython 没有问题。它指向 select('kv_label').by(Column.keys)
试图访问 JanusGraph StandardVertex
对象的情况。鉴于您更新的问题,我可以很容易地在 TinkerGraph 中重现该问题:
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
这与您最初的问题截然不同,这就是我无法重新创建它的原因。您期望流中的 inject()
中只有 key/value 对,但实际上它还有其他内容:
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]
当 v[2]
进入 select("props").by(keys)
时,您会遇到我描述的异常。您可以通过将 inject()
移动到开头或使用 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]
我不确定哪个更直观。当我需要一些东西来开始遍历时,我倾向于更喜欢 inject()
,但是你有 addV()
把对象放在开始,所以 inject()
在那里看起来很笨拙,尤其是因为 addV()
只是替换给定的 Map
。在这种情况下,我认为使用 withSideEffect()
更明确地告诉阅读本文的人意图是什么。
仅供以后偶然发现此问题的人参考。
我找到了一个使用匿名遍历而不是注入的更简单的解决方案:
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))
查询应该如下:
- 如果两个顶点之间存在边:return边
- else:创建边,根据字典设置属性,return 边。
如果 traversal
是原始遍历,则以下内容有效。
如果 traversal
已经包含一些其他步骤(例如创建顶点)
它因以下错误而崩溃。
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
如果我 iterate()
injecting
之前的遍历,它会起作用。但出于性能原因,我想避免迭代。
有什么想法吗?
编辑:
我做了更多测试。预先添加顶点是可行的。 将它们添加到同一个查询中不会。
这个有效:
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]
这失败了:
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
作为初始点,您不需要遍历中的第一个 V
。您只需要从 inject()
开始。如果您从 V()
开始,您最终会对图中的每个顶点执行以下步骤。
就是说,我没有发现您的遍历有问题,并且在我将它适应现代玩具图后,它与 TinkerGraph 一起工作得很好:
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]
您可能希望在此遍历中获得 dedup()
结果,因为在第 5 行给出其 unfold()
的情况下,地图中的每个 属性 键都会得到一个结果。
您收到的错误是服务器端错误,我认为 gremlinpython 没有问题。它指向 select('kv_label').by(Column.keys)
试图访问 JanusGraph StandardVertex
对象的情况。鉴于您更新的问题,我可以很容易地在 TinkerGraph 中重现该问题:
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
这与您最初的问题截然不同,这就是我无法重新创建它的原因。您期望流中的 inject()
中只有 key/value 对,但实际上它还有其他内容:
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]
当 v[2]
进入 select("props").by(keys)
时,您会遇到我描述的异常。您可以通过将 inject()
移动到开头或使用 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]
我不确定哪个更直观。当我需要一些东西来开始遍历时,我倾向于更喜欢 inject()
,但是你有 addV()
把对象放在开始,所以 inject()
在那里看起来很笨拙,尤其是因为 addV()
只是替换给定的 Map
。在这种情况下,我认为使用 withSideEffect()
更明确地告诉阅读本文的人意图是什么。
仅供以后偶然发现此问题的人参考。 我找到了一个使用匿名遍历而不是注入的更简单的解决方案:
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))