Математика значений свойств, которые могут не существовать

Вот запрос (gremlin-python; tinkerpop v3.3.3), который вставляет узел со свойствами «положительный» и «отрицательный», затем вычитает один из другого и выводит результат:

g.withSack(0).addV('test').property('positive', 2).property('negative', 3) \
                            .sack(assign).by('positive') \
                            .sack(minus).by('negative') \
                            .sack().next()
Out[13]: -1

Выполнение того же запроса, за исключением того, что одно из этих свойств отсутствует, приводит к ошибке:

g.withSack(0).addV('test').property('positive', 2) \
                            .sack(assign).by('positive') \
                            .sack(minus).by('negative') \
                            .sack().next()
Out[13]: ... GremlinServerError: 500: The property does not exist as the key has no associated value for the provided element: v[36]:negative

Я могу обойти это, объединив четыре возможных случая:

g.withSack(0).addV('test').property('positive', 2) \
    .coalesce(has('positive').has('negative').sack(assign).by('positive').sack(minus).by('negative').sack(), \
                has('positive').values('positive'), \
                has('negative').sack(minus).by('negative').sack(), \
                sack() \
                ).next()

Хотя это определенно некрасиво - есть ли более изящное решение? В идеале должна быть возможность вставить значение по умолчанию при отсутствии свойства. Я также пробовал использовать «математический» шаг, но он лишь немного аккуратнее и не позволяет избежать проблемы несуществующих свойств. Для ясности: в случае нескольких траверсеров я хочу получить результат для каждого из них.

0
0
296
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я думаю, что если вы используете math() или sack() для решения этой проблемы, вам, вероятно, следует подумать о том, чтобы использовать идею наличия «требуемых» свойств для этих вершин, на которых вы собираетесь выполнять эти вычисления. Это должно упростить задачу. Я действительно чувствую, что math() был бы более аккуратным, хотя вы сказали иначе:

g.V().as('a').out('knows').as('b').
  math("a - b").
    by(coalesce(values('hasSomeValue'), constant(0))).
    by(coalesce(values('missingValue'), constant(0)))

Это довольно просто, хотя, возможно, ваши примеры были предназначены для простоты, и вам нужно учитывать гораздо больше сложности.

Я полагаю, что Gremlin можно изменить, чтобы учесть второй параметр в by() как некоторый параметр по умолчанию, если первый обход ничего не вернул, таким образом:

g.V().as('a').out('knows').as('b').
  math("a - b").
    by(values('hasSomeValue'), constant(0)).
    by(values('missingValue'), constant(0))

Я бы предположил, что немного экономит набор текста, но я не уверен, что это так же понятно для чтения, как при использовании coalesce(). Думаю, мне больше нравится явное использование coalesce().

Другие вопросы по теме