Gremlin合并步骤不一致(Cosmos DB /通常吗?)

时间:2019-05-19 12:47:14

标签: gremlin

Coalesce不能作为遍历的第一步,或者如果导致合并步骤的遍历没有产生至少一个结果。在您解决问题之前,请先听我说。

如果我的图形数据库中有一个标签为'foo'和id ='bar'的顶点,并且我想添加一个标签为'baz'和id ='caz'的顶点,请执行以下Gremlin查询效果很好。

g.V('bar').coalesce(__.V('caz'), __.addV('baz').property('id', 'caz'))

如果;但是,我摆脱了查询的第一部分,查询失败。

g.coalesce(__.V('caz'), __.addV('baz').property('id', 'caz'))

类似地,如果我按如下方式重新进行查询,它也会失败。

g.V('caz').coalesce(__.V('caz'), __.addV('baz').property('id', 'caz'))

为使合并起作用,它必须具有一个或多个元素的输入集。我理解为什么当合并步骤中的步骤分别为has和hasLabel时,这种方法才有意义?但是,对于V和addV没有意义。我猜想合并的服务器实现对空或空输入步骤进行检查/返回,从而取消了对该步骤的处理。

如果这通常是与Gremlin有关的错误或改进请求,那么解决此问题将非常棒。如果仅是Cosmos DB的问题,我将直接与Microsoft通话。

在此期间,我急切地寻求解决方案以解决仅创建一个不存在的元素的挑战。我知道结合使用折叠/展开;但是,这杀死了我的遍历上下文,使先前定义的别名(使用as('xyz'))不可用。考虑到我们正在编写的查询的复杂性,我们不能失去上下文。在大规模处理数据时,我们也无法承受仅仅展开的折叠计算。

很高兴收到关于上述内容的任何建议。

热烈的问候, 塞巴

2 个答案:

答案 0 :(得分:4)

您无法使用Gremlin语言进行任何遍历。有特定的开始步骤触发遍历,通过“触发”,我的意思是将遍历放置在管道中进行处理。实际上只有几个开始步骤:V()E()inject()addV()addE()

  

我知道结合使用折叠/展开;但是,这杀死了我的遍历上下文,使得先前定义的别名(使用as('xyz'))不可用

如果可以避免的话,通常不应该过分依赖as()。通常大量使用as()的遍历可以用其他形式重写。由于您没有更多详细信息,因此我无法进一步解决。

  

在大规模处理数据时,我们也无法承受仅能展开的折叠计算。

我无法想象fold()unfold()会带来大量成本。在最坏的情况下,它将创建一个List,其中包含单个项目;在最坏的情况下,它将创建一个空列表。在类似的东西成为您需要进行重大改进的任何东西之前,您可能还需要进行大量其他性能优化工作。

所有这些,我想您可以做到:

gremlin> g = TinkerGraph.open().traversal()
==>graphtraversalsource[tinkergraph[vertices:0 edges:0], standard]
gremlin> g.inject(1).coalesce(V().has('id','caz'),addV('baz').property('id','caz'))
==>v[0]
gremlin> g.inject(1).coalesce(V().has('id','caz'),addV('baz').property('id','caz'))
==>v[0]

您可以使用inject()和一个一次性的值开始遍历,以便将某些内容放入管道中。我认为我自己更喜欢fold()unfold()方法,因为我认为它更易读。我还将确保验证我使用的图形是否实际上是在V()内的嵌入式中间遍历coalesce()使用索引的。我希望所有图表都对这种优化很聪明,但是我不能完全肯定地说。从这种意义上讲,fold()unfold()可以更好地工作,因为它们提供了一种与平台无关的方式来执行查询。

答案 1 :(得分:0)

经过一番挖掘,我意识到这个问题是特定于Gremlin语言的,而不是特定于服务器实现的(例如,这不是Cosmos DB的问题)。因此,我采用了两种“不存在时添加”模式。

对于上下文,我们使用Gremlin配方提供程序模式,该模式可确保在整个产品中为通用任务维护通用约定。因此,当我有一个要创建的元素(边或顶点)时,我将其传递给配方提供者以返回带有addE / addV和生成的属性语义的遍历。此问题源于生成支持“如果不存在则添加”模式的配方。

为解决此问题,我向配方提供者传递了一个布尔值标志,该标志告知提供者是否使用折叠/展开语义。这样,如果添加配方发生在遍历的开始,则应用程序将使用折叠/展开语义;如果不是一开始,就不会折叠/展开。虽然可以将口红涂在猪身上作为一种解决方法,但我们的应用程序使用的大多数添加配方都不会在遍历开始时出现。

举个例子,假设我有三个使用标签vTest和ID v1-id,v2-id和v3-id的顶点,则由Gremlin配方提供程序生成的Gremlin查询将如下所示:

g.V('v1-id')
  .has('partitionKey','v1')
  .fold()
  .coalesce(
    __.unfold(),
    __.addV('vTest')
      .property('id','v1-id')
      .property('partitionKey','v1')
  ).coalesce(
    __.V('v2-id')
      .has('partitionKey','v2'),
    __.addV('vTest')
      .property('id','v2-id')
      .property('partitionKey','v2')
  ).coalesce(
    __.V('v3-id')
      .has('partitionKey','v3'),
    __.addV('vTest')
      .property('id','v3-id')
      .property('partitionKey','v3')
  )

由于保证查询的每个部分都返回一个结果,因此coalesce()始终有效。但是,我确定你会同意的,给猪涂上口红。

不幸的是,对我们来说,应用中的所有用户注册都会受到fold() / unfold()方法的影响,因为该过程涉及创建第一个顶点。我当然希望将来能对Gremlin进行更新,以合并或采取其他步骤来处理条件。