#gremlin #tinkerpop #tinkerpop3 #gremlin-server #gremlinjs
#gremlin #tinkerpop #tinkerpop3 #gremlin-сервер #gremlinjs
Вопрос:
Первый запрос, выполняемый в моем проекте, выполняется в потенциально пустой базе данных и создает некоторые вершины, если они еще не созданы, поэтому мой запрос не может начинаться с V()
или E()
, поскольку база данных может быть пустой, также не может начинаться с addE()
, потому что сначала мне нужно проверить, не создано ли ребро, я нашел следующее решение, используя inject()
но это выглядит как взлом:
g.inject("").union(
coalesce(V().has("question", "questionId", 0), addV("question").property("questionId", 0)),
coalesce(V().has("question", "questionId", 1), addV("question").property("questionId", 1)),
coalesce(V().has("question", "questionId", 2), addV("question").property("questionId", 2))
)
Есть ли способ написать это элегантным способом, без чего-либо, что выглядит хакерским?
Комментарии:
1. возможно, я просто слишком долго занимался Gremlin, но
g.inject(0)
мне это не кажется взломом. когда я думаю, что что-то должно быть в потоке обхода, чтобы в первую очередь был поток, есть что-то о введении одноразового значения, которое имеет смысл для меня. хотя я полагаю, что у вас есть ответ на этот вопрос ниже, который используетV()
, какой другой синтаксис мог бы быть лучше в случаях, когда вы не смогли?2. Я согласен, что мое решение выглядит не более чем взломом по сравнению с тем, что указано в ответе. Я считаю что-то взломом, когда вы используете инструмент, созданный для совершенно другой цели, чтобы обойти проблему. Цель inject — добавить данные в обход, а не обойти запрос, который иначе не запускается. Я думаю, что gremlin должен реализовать что-то вроде
g.startEmptyTraversal()
чего-то, сделанного специально для этой цели, иначе это похоже на взлом.3. просто для ясности
inject(0)
меня это не особо беспокоит, как и ответ от bechbd, но вы не первый, кому это не нравитсяinject(0)
, поэтому я подумал, что стоит немного обсудить, чтобы узнать, есть ли у вас какие-либо мысли. я думаю, что явноеstartEmpty()
слишком сильно нарушает ожидаемую семантику обхода. однако мне интересно, могут ли такие шаги, какunion()
илиcoalesce()
, быть шагами запуска, тогдаg.coalesce(V().has('name','alice'), addV().property('name','alice'))
или подобное было бы возможно. не уверен, каковы последствия, но я сделаю заметку, чтобы обдумать это дальше. Спасибо.
Ответ №1:
Этот сценарий может быть обработан с помощью шаблона upsert с помощью fold()/unfold()
шаблона, описанного здесь. Это будет выглядеть как приведенный ниже код:
g.V().
has("question", "questionId", 0).
fold().
coalesce(unfold(), addV("question").property("questionId", 0)).
V().
has("question", "questionId", 1).
fold().
coalesce(unfold(), addV("question").property("questionId", 1)).
V().
has("question", "questionId", 2).
fold().
coalesce(unfold(), addV("question").property("questionId", 2))
Комментарии:
1. Вероятно, альтернативы нет, но для меня это также выглядит как взлом, потому что вам нужно выполнить fold () и unfold (), вы добавляете дополнительные вычисления и используете что-то, созданное для совершенно другой цели, просто потому, что если вы не добавите это, вы не сможете написать запрос
2. ИМО,
fold().coalesce(unfold(),...)
шаблон более «гремлинский» (сродни python, являющемуся «pythonic») в том смысле, что шаблон запроса фактически выполняет обход графика для выполнения условной записи в более императивном стиле. Где какinject(0)
или (если бы это поддерживалось) начинать сcoalesce()
напрямую означало бы пытаться написать этот запрос в более декларативном стиле. Использованиеfold()
/unfold()
также может не добавить дополнительных вычислений. Каждая графическая база данных TinkerPop будет анализировать, оптимизировать и выполнять эти запросы по-разному. Многие оптимизируют этот шаблон, поскольку он очень хорошо известен.