为什么需要 fold/unfold 使用 coalesce 进行条件插入?
Why do you need to fold/unfold using coalesce for a conditional insert?
我正在尝试了解这种条件插入模式的工作原理:
g.V()
.hasLabel('person').has('name', 'John')
.fold()
.coalesce(
__.unfold(),
g.addV('person').property('name', 'John')
).next();
fold/unfold 的目的是什么?为什么这些是必要的,为什么这不起作用:
g.V()
.coalesce(
__.hasLabel('person').has('name', 'John'),
g.addV('person').property('name', 'John')
).next();
折叠然后展开的模式对我来说似乎是多余的,但上面的结果并不相同。
考虑一下当您执行以下操作时会发生什么:
gremlin> g = TinkerFactory.createModern().traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> g.V().has('name','marko')
==>v[1]
gremlin> g.V().has('name','stephen')
gremlin>
对于 "marko" 你 return 一些东西而对于 "stephen" 你没有。 "stephen" 案例是需要注意的案例,因为这是 fold()
在此模式中真正变得重要的案例。当该遍历 return 什么都没有时,您之后添加的任何步骤都不会出现 Traverser
以触发这些步骤中的操作。因此,即使是以下也不会添加顶点:
gremlin> g.V().has('name','stephen').addV('person')
gremlin>
但是看看如果我们 fold()
:
会发生什么
gremlin> g.V().has('name','stephen').fold()
==>[]
fold()
是一个减少障碍的步骤,因此会急切地评估到该点的遍历和 return 内容作为 List
即使该遍历的内容达到那一点不会产生任何结果(在这种情况下,如您所见,您会得到一个空列表)。如果你有一个空的 List
那个空的 List
是一个 Traverser
流经遍历,因此未来的步骤将触发:
gremlin> g.V().has('name','stephen').fold().addV('person')
==>v[13]
所以这就解释了为什么我们 fold()
因为我们正在检查 "John" 在你的例子中是否存在,如果他被发现那么他将存在于 List
并且当那个 List
with "John" hits coalesce()
它的第一个检查将是 unfold()
that List
with "John" and return that Vertex
- 完毕。如果 List
为空并且 return 什么都没有,因为 "John" 不存在那么它将添加顶点(顺便说一下,你不需要前面的 "g." addV()
,它应该只是一个匿名遍历,因此 __.addV('person')
)。
谈到你的例子,我首先要指出,我认为你想问这个问题:
g.V().
coalesce(
__.has('person','name', 'John'),
__.addV('person').property('name', 'John'))
这是一个完全不同的查询。在此遍历中,您说的是迭代所有顶点并为每个顶点执行 coalesce()
中的内容。您可以通过将 addV()
替换为 constant('x')
:
来相当清楚地看到这一点
gremlin> g = TinkerFactory.createModern().traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> g.V().
......1> coalesce(
......2> has('person','name', 'John'),
......3> constant('x'))
==>x
==>x
==>x
==>x
==>x
==>x
gremlin> g.V().
......1> coalesce(
......2> has('person','name', 'marko'),
......3> constant('x'))
==>v[1]
==>x
==>x
==>x
==>x
==>x
现在,想象一下 addV()
和 "John" 会发生什么。它会调用 addV()
6 次,每遇到一个不是 "John":
的顶点一次
gremlin> g.V().
......1> coalesce(
......2> __.has('person','name', 'John'),
......3> __.addV('person').property('name', 'John'))
==>v[13]
==>v[15]
==>v[17]
==>v[19]
==>v[21]
==>v[23]
就个人而言,我喜欢将这种逻辑包装在 Gremlin DSL - there is a good example of doing so here 中的想法。
好问题 - 我已经将 "Element Existence" 问题描述为 Gremlin Recipe 的一部分,可以阅读 here。
我正在尝试了解这种条件插入模式的工作原理:
g.V()
.hasLabel('person').has('name', 'John')
.fold()
.coalesce(
__.unfold(),
g.addV('person').property('name', 'John')
).next();
fold/unfold 的目的是什么?为什么这些是必要的,为什么这不起作用:
g.V()
.coalesce(
__.hasLabel('person').has('name', 'John'),
g.addV('person').property('name', 'John')
).next();
折叠然后展开的模式对我来说似乎是多余的,但上面的结果并不相同。
考虑一下当您执行以下操作时会发生什么:
gremlin> g = TinkerFactory.createModern().traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> g.V().has('name','marko')
==>v[1]
gremlin> g.V().has('name','stephen')
gremlin>
对于 "marko" 你 return 一些东西而对于 "stephen" 你没有。 "stephen" 案例是需要注意的案例,因为这是 fold()
在此模式中真正变得重要的案例。当该遍历 return 什么都没有时,您之后添加的任何步骤都不会出现 Traverser
以触发这些步骤中的操作。因此,即使是以下也不会添加顶点:
gremlin> g.V().has('name','stephen').addV('person')
gremlin>
但是看看如果我们 fold()
:
gremlin> g.V().has('name','stephen').fold()
==>[]
fold()
是一个减少障碍的步骤,因此会急切地评估到该点的遍历和 return 内容作为 List
即使该遍历的内容达到那一点不会产生任何结果(在这种情况下,如您所见,您会得到一个空列表)。如果你有一个空的 List
那个空的 List
是一个 Traverser
流经遍历,因此未来的步骤将触发:
gremlin> g.V().has('name','stephen').fold().addV('person')
==>v[13]
所以这就解释了为什么我们 fold()
因为我们正在检查 "John" 在你的例子中是否存在,如果他被发现那么他将存在于 List
并且当那个 List
with "John" hits coalesce()
它的第一个检查将是 unfold()
that List
with "John" and return that Vertex
- 完毕。如果 List
为空并且 return 什么都没有,因为 "John" 不存在那么它将添加顶点(顺便说一下,你不需要前面的 "g." addV()
,它应该只是一个匿名遍历,因此 __.addV('person')
)。
谈到你的例子,我首先要指出,我认为你想问这个问题:
g.V().
coalesce(
__.has('person','name', 'John'),
__.addV('person').property('name', 'John'))
这是一个完全不同的查询。在此遍历中,您说的是迭代所有顶点并为每个顶点执行 coalesce()
中的内容。您可以通过将 addV()
替换为 constant('x')
:
gremlin> g = TinkerFactory.createModern().traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> g.V().
......1> coalesce(
......2> has('person','name', 'John'),
......3> constant('x'))
==>x
==>x
==>x
==>x
==>x
==>x
gremlin> g.V().
......1> coalesce(
......2> has('person','name', 'marko'),
......3> constant('x'))
==>v[1]
==>x
==>x
==>x
==>x
==>x
现在,想象一下 addV()
和 "John" 会发生什么。它会调用 addV()
6 次,每遇到一个不是 "John":
gremlin> g.V().
......1> coalesce(
......2> __.has('person','name', 'John'),
......3> __.addV('person').property('name', 'John'))
==>v[13]
==>v[15]
==>v[17]
==>v[19]
==>v[21]
==>v[23]
就个人而言,我喜欢将这种逻辑包装在 Gremlin DSL - there is a good example of doing so here 中的想法。
好问题 - 我已经将 "Element Existence" 问题描述为 Gremlin Recipe 的一部分,可以阅读 here。