Гремлин: Что, если мой запрос не может начинаться с V () или E ()?

#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 будет анализировать, оптимизировать и выполнять эти запросы по-разному. Многие оптимизируют этот шаблон, поскольку он очень хорошо известен.