【问题标题】:Gremlin Python - Add unknown number of properties to edge on edge creation if edge does not existGremlin Python - 如果边不存在,则在边创建时向边添加未知数量的属性
【发布时间】:2020-02-04 14:04:58
【问题描述】:

查询应该如下:

  • 如果两个顶点之间存在边:返回边
  • else:创建边缘,从 dict 设置属性并返回边缘。

如果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

如果我在injecting 之前遍历iterate(),它可以工作。但出于性能原因,我想避免迭代。

有什么想法吗?

编辑:

我做了更多的测试。预先添加顶点有效。 在同一个查询中添加它们不会。

这行得通:

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

【问题讨论】:

  • 我不太明白你的问题的几个方面。具体来说,我不确定我知道你所说的“原始遍历”是什么意思,我不知道你最后一句关于“迭代()......注入之前”的意思以及关于性能的观点。如果我在下面的回答没有帮助,您可能需要就这些问题进一步澄清您的问题。
  • @stephenmallette 这是一个更大的项目的一部分,该项目试图将 python 对象映射到顶点。它在解析对象图时添加多个顶点和边。当前的实现速度非常慢。我的观察是,我的 iterate() 调用越少,它的速度就越快,即 gremlin 查询的时间越长。在我上面的示例中,traversal 可以是新的,也可以已经包含多个 addV() 调用。在后一种情况下,注入中断。
  • 我认为您是在说您将多个突变组合到一个遍历中,以尝试通过减少单个请求的数量来提高性能。只是在inject() 前面添加V() 会导致您看到的失败吗?还是必须明确包含addV()?如果是这样,有多少是“几个” - 也许,只需使用导致问题的特定遍历来更新您的问题?顺便说一句,Gremlin 控制台中的失败示例将是调试此问题的最简单方法。
  • @stephenmallette 我用一个具体的例子更新了这个问题。 addV() 导致问题。 V() 工作。
  • 感谢您花时间在 Gremlin Console 中创建可重现的条件。这几乎总是使解决问题变得容易。我已经更新了我的答案。

标签: gremlin tinkerpop3 janusgraph


【解决方案1】:

作为初始点,您在遍历中不需要第一个 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() 中的键/值对,但实际上它还有其他内容:

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() 更明确地告诉阅读本文的人的意图是什么。

【讨论】:

    【解决方案2】:

    仅供将来可能偶然发现此问题的任何人参考。 我找到了一个使用匿名遍历而不是注入更简单的解决方案:

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

    【讨论】:

      猜你喜欢
      • 2022-06-12
      • 1970-01-01
      • 2019-02-26
      • 2017-07-05
      • 1970-01-01
      • 1970-01-01
      • 2017-04-25
      • 2019-07-26
      • 1970-01-01
      相关资源
      最近更新 更多