如何获得满足特定条件的所有顶点的子图

时间:2017-07-03 08:54:28

标签: azure-cosmosdb gremlin tinkerpop3 gremlin-server

Document Revision 是两个驻留在我们的域逻辑特定层中的对象。

文档代表了您能想到的任何材料纸的抽象。也就是说 - 每个合同,发票或图纸都可以称为文档

另一方面,文档的材料表示是 Revision :建筑工程师在现场收到的纸张清单代表修订版设计者创建的文档。如果由于错误或需求更改而必须更改图形中的某些内容,则会在现场显示相同文档修订版#2

Revision 可能包含指向其他 Documents 的链接;因此,我们可以描述汽车,车门,发动机,车轮等之间的关系,以及每个元素独立演变的可能性,同时保持与其他元素的联系。

显示典型的DAG

Car elements - Documents and Revisions

我设法使用C# Graph API将所有顶点和边插入到CosmosDB中。 我设法遍历图表并执行简单查询,以便查找汽车有多少修改,或者发动机在最初创建时是否有涡轮增压器。 但是,我正在努力编写一个复杂的查询,它只返回每个部分或汽车的最新版本,或者返回到2016-08-10的汽车状态的查询。

截至2017-01-03的汽车状况: Finished car

2016-08-10赛车的状态: Car's engine has no turbocharger yet

当遍历访问顶点的后代(其" out()")时,我无法找到获得最近创建的方法并继续遍历而无需深入研究其他。如果你建议我一个只从图片中返回彩色顶点的表达式,我将不胜感激。

1 个答案:

答案 0 :(得分:6)

虽然图片很有用,但在询问有关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()

通常,回答问题的人需要更多时间来为问题创建示例图,而不是开发提供答案的Gremlin。

无论如何,这是使用“8/10/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:[]]]]]

这是相同的遍历日期 - “1/1/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”被排除在外,因为它是“1/1/2017”之后的唯一顶点 - 树的其余部分存在。

一些注意事项:

  1. 我将您的日期转换为多头以便于比较。我不确定CosmosDB是否对lte的{​​{1}}谓词的日期处理得很好,但如果确实如此,你可能更愿意选择那条路线。
  2. has()步允许在树中进行任意深度遍历,但请注意它在repeat()之后包含的重复逻辑 - 这会抓住最后的“树叶” emit()循环结束,因为不再有repeat()遍历。
  3. outE()中的逻辑看起来有点复杂,但它基本上只是说当前“文档”遍历所有“修订版”,按日期降序排序并抓住第一个。一旦它具有受您关注日期控制的最新版本,请遍历其连接的任何其他文档。
  4. 我在这种情况下使用了repeat()步骤,因为CosmosDB似乎支持这一点。看起来他们还不支持tree()。 Apache TinkerPop C#Gremlin语言变体在技术上甚至不支持这一步骤 - 那里存在一些挑战,遗漏了Java唯一的功能。幸运的是,您的数据形状是树状的,因此subgraph()步骤似乎已足够。
  5. 在Groovy中,您可以通过闭包提供重复的逻辑,以使事情更容易重复使用:

    tree()

    或存储'traverseAndFilter'遍历本身及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:[]]]]] 它:

    clone()