为啥需要使用合并来折叠/展开以进行条件插入?

Posted

技术标签:

【中文标题】为啥需要使用合并来折叠/展开以进行条件插入?【英文标题】:Why do you need to fold/unfold using coalesce for a conditional insert?为什么需要使用合并来折叠/展开以进行条件插入? 【发布时间】:2019-01-17 22:43:21 【问题描述】:

我试图了解这种条件插入模式的工作原理:

g.V()
  .hasLabel('person').has('name', 'John')
  .fold()
  .coalesce(
    __.unfold(),
    g.addV('person').property('name', 'John')
  ).next();

折叠/展开的目的是什么?为什么这些是必要的,为什么这不起作用:

g.V()
  .coalesce(
    __.hasLabel('person').has('name', 'John'),
    g.addV('person').property('name', 'John')
  ).next();

折叠然后展开模式对我来说似乎是多余的,但上面的结果并没有产生相同的结果。

【问题讨论】:

有趣的模式 相关:Gremlin - only add a vertex if it doesn't exist 【参考方案1】:

考虑一下当您执行以下操作时会发生什么:

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”,您返回一些东西,而对于“stephen”,您没有。 “斯蒂芬”案例是需要注意的案例,因为这是 fold() 在此模式中真正变得重要的案例。当该遍历不返回任何内容时,您在此之后添加的任何步骤都不会出现Traverser 来触发这些步骤中的操作。因此,即使以下也不会添加顶点:

gremlin> g.V().has('name','stephen').addV('person')
gremlin> 

但是看看如果我们fold()会发生什么:

gremlin> g.V().has('name','stephen').fold()
==>[]

fold() 是一个减少障碍步骤,因此将急切地评估到该点的遍历并将内容作为List 返回,即使该遍历的内容到该点没有产生任何结果(在这种情况下,如你可以看到,你得到一个空列表)。如果你有一个空的List,那么空的List 是一个Traverser 流经遍历,因此未来的步骤将会触发:

gremlin> g.V().has('name','stephen').fold().addV('person')
==>v[13]

这就解释了为什么我们fold(),因为我们正在检查您的示例中是否存在“John”,如果找到他,那么他将存在于List 中,并且当带有“John”的List 命中@987654339 时@ 它的第一个检查将是 unfold() List 和“John”并返回 Vertex - 完成。如果List 为空并且不返回任何内容,因为“John”不存在,那么它将添加顶点(顺便说一下,您不需要 addV() 前面的“g.”,它应该只是一个匿名遍历,因此__.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 中的想法 - 有一个很好的例子来说明这样做 here。

很好的问题 - 我已经将“元素存在”问题描述为 Gremlin 食谱的一部分,可以阅读 here。

【讨论】:

很好的解释真的很有帮助。

以上是关于为啥需要使用合并来折叠/展开以进行条件插入?的主要内容,如果未能解决你的问题,请参考以下文章

html5 - 如何折叠和展开复杂的表格元素

为啥 TreeView 控件会折叠所有子节点?

RecyclerView 展开/折叠项目

基于max-height实现不定高度元素的折叠/合并,展开/收缩的动画效果

将动画添加到 ListView 以展开/折叠内容

Swft3 (RxSwift, RxCocoa) - TableView 使用响应式编程展开和折叠概念