Хотя изображения полезны, задавая вопросы о Gremlin, всегда полезно предоставить скрипт Gremlin, который может сгенерировать образец вашего графика. Например, для ваших вопросов:
graph = TinkerGraph.open()
g = graph.traversal()
g.addV('car').property('name','car').as('car').
addV('rev').property('name','car revision 1').property('date', 1470787200L).as('carV1').
addV('rev').property('name','car revision 2').property('date', 1472688000L).as('carV2').
addV('frontLeftDoor').property('name','front left door').as('frontLeftDoor').
addV('frontRightDoor').property('name','front right door').as('frontRightDoor').
addV('engine').property('name','engine').as('engine').
addV('turbocharger').property('name','turbocharger').as('turbocharger').
addV('rev').property('name','front left door revision 1').property('date',1470787200L).as('frontLeftDoorV1').
addV('rev').property('name','front left door revision 2').property('date',1472688000L).as('frontLeftDoorV2').
addV('rev').property('name','front right door revision 1').property('date',1470787200L).as('frontRightDoorV1').
addV('rev').property('name','engine revision 1').property('date',1470787200L).as('engineV1').
addV('rev').property('name','engine revision 2').property('date',1472688000L).as('engineV2').
addV('rev').property('name','engine revision 3').property('date',1483401600L).as('engineV3').
addV('rev').property('name','turbocharger revision 1').property('date',1470787200L).as('turbochargerV1').
addV('rev').property('name','turbocharger revision 2').property('date',1472688000L).as('turbochargerV2').
addE('relates').from('car').to('carV1').
addE('relates').from('car').to('carV2').
addE('relates').from('carV1').to('frontLeftDoor').
addE('relates').from('carV1').to('frontRightDoor').
addE('relates').from('carV1').to('engine').
addE('relates').from('carV2').to('frontLeftDoor').
addE('relates').from('carV2').to('frontRightDoor').
addE('relates').from('carV2').to('engine').
addE('relates').from('frontLeftDoor').to('frontLeftDoorV1').
addE('relates').from('frontLeftDoor').to('frontLeftDoorV2').
addE('relates').from('frontRightDoor').to('frontRightDoorV1').
addE('relates').from('engine').to('engineV1').
addE('relates').from('engine').to('engineV2').
addE('relates').from('engine').to('engineV3').
addE('relates').from('engineV2').to('turbocharger').
addE('relates').from('engineV3').to('turbocharger').
addE('relates').from('turbocharger').to('turbochargerV1').
addE('relates').from('turbocharger').to('turbochargerV2').iterate()
Часто человеку, отвечающему на вопрос, требуется больше времени, чтобы создать образец диаграммы для вопроса, чем разработать Гремлин, дающий ответ.
В любом случае, вот один из способов сделать это, используя «10.08.2016» в качестве «даты начала»:
gremlin> g.V().has('name','car').
......1> repeat(local(out().has('date',lte(1470787200L)).
......2> order().
......3> by('date',decr).limit(1)).
......4> out()).
......5> emit().
......6> local(out().has('date',lte(1470787200L)).
......7> order().
......8> by('date',decr).limit(1)).
......9> tree().by('name')
==>[car:[car revision 1:[front right door:[front right door revision 1:[]],engine:[engine revision 1:[]],front left door:[front left door revision 1:[]]]]]
Вот тот же ход с другой датой - «01.01.2017»:
gremlin> g.V().has('name','car').
......1> repeat(local(out().has('date',lte(1483228800L)).
......2> order().
......3> by('date',decr).limit(1)).
......4> out()).
......5> emit().
......6> local(out().has('date',lte(1483228800L)).
......7> order().
......8> by('date',decr).limit(1)).
......9> tree().by('name')
==>[car:[car revision 2:[front right door:[front right door revision 1:[]],engine:[engine revision 2:[turbocharger:[turbocharger revision 2:[]]]],front left door:[front left door revision 2:[]]]]]
В этом случае обратите внимание на то, что "ревизия движка 3" исключена, поскольку это единственная вершина после "01.01.2017" - остальная часть дерева присутствует.
Несколько примечаний:
- Я преобразовал ваши даты в длинные для облегчения сравнения. Я не уверен, что CosmosDB имеет удобную обработку дат относительно предиката
lte
для has()
, но если это так, вы, вероятно, предпочтете пойти по этому пути.
- Шаг
repeat()
допускает произвольный обход глубины в дереве, но обратите внимание на дублированную логику, которую он содержит сразу после emit()
- это захватывает последние "листья дерева", так как внутри repeat()
цикл заканчивается, потому что больше нет outE()
для траверс.
- Логика в
repeat()
выглядит немного сложной, но в основном это просто говорит о том, что текущий «документ» проходит по всем «ревизиям», отсортирует дату в порядке убывания и захватит первую. Как только он получит самую последнюю версию, которая контролируется датой, которая вам нужна, перейдите к любым другим документам, к которым он подключен.
- В этом случае я использовал шаг
tree()
, поскольку CosmosDB, похоже, его поддерживает. Не похоже, что они еще поддерживают subgraph()
. Технически этот шаг даже не поддерживается в Apache TinkerPop C # Gremlin Language Variant - там есть некоторые проблемы, которые, к сожалению, оставляют только возможности Java. К счастью, форма ваших данных древовидная, поэтому достаточно tree()
шагов.
В Groovy вы можете предоставить повторяющуюся логику в виде замыкания, чтобы сделать вещи более пригодными для повторного использования:
gremlin> traverseAndFilter = { out().has('date',lte(1470787200L)).
......1> order().
......2> by('date',decr).limit(1) }
==>groovysh_evaluate$_run_closure1@1d12e953
gremlin> g.V().has('name','car').
......1> repeat(local(traverseAndFilter()).out()).
......2> emit().
......3> local(local(traverseAndFilter())).
......4> tree().by('name')
==>[car:[car revision 1:[front right door:[front right door revision 1:[]],engine:[engine revision 1:[]],front left door:[front left door revision 1:[]]]]]
или сохраните сам обход traverseAndFilter и clone()
его:
gremlin> traverseAndFilter = out().has('date',lte(1470787200L)).
......1> order().
......2> by('date',decr).limit(1);[]
gremlin> g.V().has('name','car').
......1> repeat(local(traverseAndFilter.clone()).out()).
......2> emit().
......3> local(local(traverseAndFilter.clone())).
......4> tree().by('name')
==>[car:[car revision 1:[front right door:[front right door revision 1:[]],engine:[engine revision 1:[]],front left door:[front left door revision 1:[]]]]]
person
stephen mallette
schedule
03.07.2017