Gremlin Python - добавление неизвестного количества свойств к ребру при создании ребра, если ребро не существует - PullRequest
1 голос
/ 07 октября 2019

Запрос должен быть следующим:

  • Если существует ребро между двумя вершинами: вернуть ребро
  • else: создать ребро, задать свойства из условия и вернутьedge.

Следующее работает, если 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

Если I iterate() обход до injecting, это работает. Но я бы хотел избежать итерации по соображениям производительности.

Есть идеи?

edit:

Я провел еще несколько тестов. Добавление вершин заранее работает. Добавление их в тот же запрос не дает.

Это работает:

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

Ответы [ 2 ]

2 голосов
/ 07 октября 2019

В качестве начальной точки вам не нужен первый 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() результаты этого обхода, так как вы получите один результат для каждого ключа свойства на карте, учитывая его unfold() в строке 5.

Ошибка, которую вы получаете, является ошибкой на стороне сервера, а я нетдумаю проблема с 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), вы получаете исключение Iописано. Вы можете исправить это, переместив 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() более явно говорит кому-то, читающему это, каково намерение.

1 голос
/ 22 октября 2019

Просто для справки для тех, кто может наткнуться на это в будущем. Я нашел решение, которое намного проще, используя анонимный обход вместо инъекции:

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