Gremlin 图遍历用法词典步骤A-M

本文详细介绍了TinkerPop的Gremlin图遍历的多个步骤,包括通用步骤、终端步骤、AddE步骤、AddV步骤、Aggregate步骤、All步骤、And步骤等,展示了如何在图数据库操作中进行节点和边的添加、聚合、过滤等操作,以及各种条件判断和组合使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

TinkerPop Gremlin 图遍历用法词典步骤A-M 点击标题免费查看全文


Gremlin步骤被链接在一起以生成实际的遍历,并通过 GraphTraversalSource上的 开始步骤触发。

重要提示 关于Gremlin语言的更多详细信息可以在Gremlin语义部分中的提供程序文档中找到。

通用步骤

有五个通用步骤,每个步骤都有一个遍历和一个lambda表示,后面描述的所有其他具体步骤都是基于这些通用步骤扩展的。

步骤 描述
map(Traversal<S, E>) map(Function<Traverser<S>, E>) 将traverser映射到下一步要处理的某个类型为E的对象。
flatMap(Traversal<S, E>) flatMap(Function<Traverser<S>, Iterator<E>>) 将traverser映射到一个E对象的迭代器,该迭代器将流式传递给下一步。
filter(Traversal<?, ?>) filter(Predicate<Traverser<S>>) 将traverser映射为true或false,其中false不会将traverser传递给下一步。
sideEffect(Traversal<S, S>) sideEffect(Consumer<Traverser<S>>) 对traverser执行某些操作,并将其传递给下一步。
branch(Traversal<S, M>) branch(Function<Traverser<S>,M>) 将traverser拆分为由M标记索引的所有遍历。
警告 为了教育目的,演示了lambda步骤,因为它们代表了Gremlin语言的基本构造。在实践中,应避免使用lambda步骤,而应使用它们的遍历表示,并且存在遍历验证策略来禁止使用它们,除非明确"关闭"。有关lambda的问题的更多信息,请阅读A Note on Lambdas

Traverser<S>对象提供对以下内容的访问:

  1. 当前遍历的S对象 - Traverser.get()
  2. 遍历器当前遍历的路径 - Traverser.path()
    1. 获取特定路径历史记录对象的快捷方式 - Traverser.path(String) == Traverser.path().get(String)
  3. 遍历器已经经过当前循环的次数 - Traverser.loops()
  4. 由该遍历器表示的对象数量 - Traverser.bulk()
  5. 与此遍历器关联的局部数据结构 - Traverser.sack()
  6. 与遍历相关的副作用 - Traverser.sideEffects()
    1. 获取特定副作用的快捷方式 - Traverser.sideEffect(String) == Traverser.sideEffects().get(String)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

gremlin> g.V(1).out().values('name') //// (1)
==>lop
==>vadas
==>josh
gremlin> g.V(1).out().map {it.get().value('name')} //// (2)
==>lop
==>vadas
==>josh
gremlin> g.V(1).out().map(values('name')) //// (3)
==>lop
==>vadas
==>josh
g.V(1).out().values('name') //// (1)
g.V(1).out().map {it.get().value('name')} //// (2)
g.V(1).out().map(values('name')) //3
  1. 从顶点1出发,获取相邻顶点的名称值。
  2. 相同的操作,但使用lambda来访问名称属性值。
  3. 再次相同的操作,但使用map()的遍历表示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

gremlin> g.V().filter {it.get().label() == 'person'} //// (1)
==>v[1]
==>v[2]
==>v[4]
==>v[6]
gremlin> g.V().filter(label().is('person')) //// (2)
==>v[1]
==>v[2]
==>v[4]
==>v[6]
gremlin> g.V().hasLabel('person') //// (3)
==>v[1]
==>v[2]
==>v[4]
==>v[6]
g.V().filter {it.get().label() == 'person'} //// (1)
g.V().filter(label().is('person')) //// (2)
g.V().hasLabel('person') //3
  1. 只有带有"person"标签的顶点才能通过过滤器。
  2. 相同的操作,但使用filter()的遍历表示。
  3. 更具体的has()-step实际上是使用相应谓词的filter()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

gremlin> g.V().hasLabel('person').sideEffect(System.out.&println) //// (1)
v[1]
==>v[1]
v[2]
==>v[2]
v[4]
==>v[4]
v[6]
==>v[6]
gremlin> g.V().sideEffect(outE().count().aggregate(local,"o")).
               sideEffect(inE().count().aggregate(local,"i")).cap("o","i") //// (2)
==>[i:[0,0,1,1,1,3],o:[3,0,0,0,2,1]]
g.V().hasLabel('person').sideEffect(System.out.&println) //// (1)
g.V().sideEffect(outE().count().aggregate(local,"o")).
      sideEffect(inE().count().aggregate(local,"i")).cap("o","i") //2
  1. sideEffect()中的任何内容都会传递到下一步,但可能会发生一些干预操作。
  2. 计算每个顶点的出度和入度。两个sideEffect()接收相同的顶点。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

gremlin> g.V().branch {it.get().value('name')}.
               option('marko', values('age')).
               option(none, values('name')) //// (1)
==>29
==>vadas
==>lop
==>josh
==>ripple
==>peter
gremlin> g.V().branch(values('name')).
               option('marko', values('age')).
               option(none, values('name')) //// (2)
==>29
==>vadas
==>lop
==>josh
==>ripple
==>peter
gremlin> g.V().choose(has('name','marko'),
                      values('age'),
                      values('name')) //// (3)
==>29
==>vadas
==>lop
==>josh
==>ripple
==>peter
g.V().branch {it.get().value('name')}.
      option('marko', values('age')).
      option(none, values('name')) //// (1)
g.V().branch(values('name')).
      option('marko', values('age')).
      option(none, values('name')) //// (2)
g.V().choose(has('name','marko'),
             values('age'),
             values('name')) //3
  1. 如果顶点是"marko",则获取他的年龄,否则获取顶点的名称。
  2. 相同的操作,但使用branch()的遍历表示。
  3. 更具体的基于布尔值的choose()-step实际上是branch()的实现。

终端步骤

通常,当一个步骤连接到一个遍历中时,将返回一个新的遍历。通过这种方式,遍历可以以流畅单子的方式逐步构建起来。然而,有些步骤并不返回遍历,而是执行遍历并返回结果。这些步骤被称为**终端步骤(terminal)**并通过下面的示例进行解释。

gremlin> g.V().out('created').hasNext() //// (1)
==>true
gremlin> g.V().out('created').next() //// (2)
==>v[3]
gremlin> g.V().out('created').next(2) //// (3)
==>v[3]
==>v[5]
gremlin> g.V().out('nothing').tryNext() //// (4)
==>Optional.empty
gremlin> g.V().out('created').toList() //// (5)
==>v[3]
==>v[5]
==>v[3]
==>v[3]
gremlin> g.V().out('created').toSet() //// (6)
==>v[3]
==>v[5]
gremlin> g.V().out('created').toBulkSet() //// (7)
==>v[3]
==>v[3]
==>v[3]
==>v[5]
gremlin> results = ['blah',3]
==>blah
==>3
gremlin> g.V().out('created').fill(results) //// (8)
==>blah
==>3
==>v[3]
==>v[5]
==>v[3]
==>v[3]
gremlin> g.addV('person').iterate() //// (9)
g.V().out('created').hasNext() //// (1)
g.V().out('created').next() //// (2)
g.V().out('created').next(2) //// (3)
g.V().out('nothing').tryNext() //// (4)
g.V().out('created').toList() //// (5)
g.V().out('created').toSet() //// (6)
g.V().out('created').toBulkSet() //// (7)
results = ['blah',3]
g.V().out('created').fill(results) //// (8)
g.addV('person').iterate() //9
  1. hasNext() 确定是否有可用的结果(在 gremlin-javascript 中不支持)。
  2. next() 返回下一个结果。
  3. next(n) 返回列表中的下一个 n 个结果(在 gremlin-javascript 或 Gremlin.NET 中不支持)。
  4. tryNext() 返回一个 Optional,因此是 hasNext()/next() 的组合(仅支持 JVM 语言)。
  5. toList() 返回所有结果的列表。
  6. toSet() 返回所有结果的集合,并且会去除重复项(在 gremlin-javascript 中不支持)。
  7. toBulkSet() 返回所有结果的加权集合,并且通过加权保留重复项(仅支持 JVM 语言)。
  8. fill(collection) 将所有结果放入提供的集合中,并在完成时返回集合(仅支持 JVM 语言)。
  9. iterate() 不完全符合终端步骤的定义,因为它不返回结果,但仍然返回一个遍历。然而,它作为终端步骤的行为是迭代遍历并生成副作用,而不返回实际结果。

还有一个名为 promise() 的终端步骤,只能与连接到 Gremlin ServerRGPs 的远程遍历一起使用。它启动了一个承诺,以在将来执行当前 Traversal 上的函数。

最后,explain() 步骤也是一个终端步骤,并在自己的部分中进行了描述。

AddE 步骤

Reasoning 是将数据中的隐含信息变为显式的过程。图中的对象,即顶点和边,是显式的。图中的遍历是隐含的。换句话说,遍历通过定义暴露了意义。例如,考虑"co-developer"的概念。如果两个人共同参与了同一个项目,那么他们就是共同开发者。这个概念可以表示为遍历,并且因此"co-developers"的概念可以得出。而且,通过addE()步骤(map/sideEffect)可以将隐含的东西变为显式的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

gremlin> g.V(1).as('a').out('created').in('created').where(neq('a')).
           addE('co-developer').from('a').property('year',2009) //// (1)
==>e[0][1-co-developer->4]
==>e[13][1-co-developer->6]
gremlin> g.V(3,4,5).aggregate('x').has('name','josh').as('a').
           select('x').unfold().hasLabel('software').addE('createdBy').to('a') //// (2)
==>e[14][3-createdBy->4]
==>e[15][5-createdBy->4]
gremlin> g.V().as('a').out('created').addE('createdBy').to('a').property('acl','public') //// (3)
==>e[16][3-createdBy->1]
==>e[17][5-createdBy->4]
==>e[18][3-createdBy->4]
==>e[19][3-createdBy->6]
gremlin> g.V(1).as('a').out('knows').
           addE('livesNear').from('a').property('year',2009).
           inV().inE('livesNear').values('year') //// (4)
==>2009
==>2009
gremlin> g.V().match(
                 __.as('a').out('knows').as('b'),
                 __.as('a').out('created').as('c'),
                 __.as('b').out('created').as('c')).
               addE('friendlyCollaborator').from('a').to('b').
                 property(id,23).property('project',select('c').values('name')) //// (5)
==>e[23][1-friendlyCollaborator->4]
gremlin> g.E(23).valueMap()
==>[project:lop]
gremlin> vMarko = g.V().has('name','marko').next()
==>v[1]
gremlin> vPeter = g.V().has('name','peter').next()
==>v[6]
gremlin> g.V(vMarko).addE('knows').to(vPeter) //// (6)
==>e[22][1-knows->6]
gremlin> g.addE('knows').from(vMarko).to(vPeter) //// (7)
==>e[24][1-knows->6]
g.V(1).as('a').out('created').in('created').where(neq('a')).
  addE('co-developer').from('a').property('year',2009) //// (1)
g.V(3,4,5).aggregate('x').has('name','josh').as('a').
  select('x').unfold().hasLabel('software').addE('createdBy').to('a') //// (2)
g.V().as('a').out('created').addE('createdBy').to('a').property('acl','public') //// (3)
g.V(1).as('a').out('knows').
  addE('livesNear').from('a').property('year',2009).
  inV().inE('livesNear').values('year') //// (4)
g.V().match(
        __.as('a').out('knows').as('b'),
        __.as('a').out('created').as('c'),
        __.as('b').out('created').as('c')).
      addE('friendlyCollaborator').from('a').to('b').
        property(id,23).property('project',select('c').values('name')) //// (5)
g.E(23).valueMap()
vMarko = g.V().has('name','marko').next()
vPeter = g.V().has('name','peter').next()
g.V(vMarko).addE('knows').to(vPeter) //// (6)
g.addE('knows').from(vMarko).to(vPeter) //7
  1. 在 Marko 和他的合作者之间添加一个带有 year 属性的 co-developer 边。
  2. 从 josh-顶点到 lop-和 ripple-顶点添加 createdBy 边。
  3. 对于所有创建的边,添加一个相反的 createdBy 边。
  4. 新创建的边是可遍历对象。
  5. 将两个任意绑定在遍历中通过 from()to() 进行连接,其中对于支持用户提供的 id 的图可以提供 id
  6. 在 Marko 和 Peter 之间添加一个边,给定定向(分离的)顶点引用。
  7. 在 Marko 和 Peter 之间添加一个边,给定定向(分离的)顶点引用。

其他参考资料

addE(String), addE(Traversal)

AddV 步骤

addV()-步骤用于向图中添加顶点(map/sideEffect)。对于每个传入的对象,都会创建一个顶点。此外,GraphTraversalSource 维护了一个 addV() 方法。

gremlin> g.addV('person').property('name','stephen')
==>v[0]
gremlin> g.V().values('name')
==>stephen
==>marko
==>vadas
==>lop
==>josh
==>ripple
==>peter
gremlin> g.V().outE('knows').addV().property('name','nothing')
==>v[13]
==>v[15]
gremlin> g.V().has('name','nothing')
==>v[13]
==>v[15]
gremlin> g.V().has('name','nothing').bothE()
g.addV('person').property('name','stephen')
g.V().values('name')
g.V().outE('knows').addV().property('name','nothing')
g.V().has('name','nothing')
g.V().has('name','nothing').bothE()

其他参考资料

addV(), addV(String), addV(Traversal)

Aggregate 步骤

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

aggregate()-步骤(sideEffect)用于将遍历的特定点上的所有对象聚合到一个 Collection 中。此步骤使用 Scope 来帮助确定聚合行为。对于 global 范围,这意味着该步骤将使用急切求值,即在继续之前不会有任何对象,直到所有之前的对象都已完全聚合。急切求值模型在需要将某个特定点的所有内容用于未来计算的情况下至关重要。默认情况下,当没有提供 Scopeaggregate() 重载调用时,默认为 global。以下是一个示例。

gremlin> g.V(1).out('created') //// (1)
==>v[3]
gremlin> g.V(1).out('created').aggregate('x') //// (2)
==>v[3]
gremlin> g.V(1).out('created').aggregate(global, 'x') //// (3)
==>v[3]
gremlin> g.V(1).out('created').aggregate('x').in('created') //// (4)
==>v[1]
==>v[4]
==>v[6]
gremlin> g.V(1).out('created').aggregate('x').in('created').out('created') //// (5)
==>v[3]
==>v[5]
==>v[3]
==>v[3]
gremlin> g.V(1).out('created').aggregate('x').in('created').out('created').
                where(without('x')).values('name') //// (6)
==>ripple
g.V(1).out('created') //// (1)
g.V(1).out('created').aggregate('x') //// (2)
g.V(1).out('created').aggregate(global, 'x') //// (3)
g.V(1).out('created').aggregate('x').in('created') //// (4)
g.V(1).out('created').aggregate('x').in('created').out('created') //// (5)
g.V(1).out('created').aggregate('x').in('created').out('created').
       where(without('x')).values('name') //6
  1. Marko 创建了什么?
  2. 聚合他的所有创建。
  3. 与上一行完全相同。
  4. Marko 的合作者是谁?
  5. Marko 的合作者创建了什么?
  6. Marko 的合作者创建的项目中,Marko 尚未创建的有哪些?

推荐系统中,使用了上述模式:

"用户 A 喜欢什么?其他人喜欢什么?其他人喜欢的东西中,A 还没有喜欢过的有哪些?"

最后,aggregate()-步骤可以通过 by()-投影进行调节。

gremlin> g.V().out('knows').aggregate('x').cap('x')
==>[v[2],v[4]]
gremlin> g.V().out('knows').aggregate('x').by('name').cap('x')
==>[vadas,josh]
gremlin> g.V().out('knows').aggregate('x').by('age').cap('x') //// (1)
==>[27,32]
g.V().out('knows').aggregate('x').cap('x')
g.V().out('knows').aggregate('x').by('name').cap('x')
g.V().out('knows').aggregate('x').by('age').cap('x')  //1
  1. 对于不是所有顶点都具有生产性(productive)的 “age” 属性,这些值不会包含在聚合中。

对于 local 范围,聚合将以惰性方式进行。

注意 在 3.4.3 之前,local 聚合(即惰性)求值由 store()-步骤处理。
gremlin> g.V().aggregate(global, 'x').limit(1).cap('x')
==>[v[1],v[2],v[3],v[4],v[5],v[6]]
gremlin> g.V().aggregate(local, 'x').limit(1).cap('x')
==>[v[1]]
gremlin> g.withoutStrategies(EarlyLimitStrategy).V().aggregate(local,'x').limit(1).cap('x')
==>[v[1],v[2]]
g.V().aggregate(global, 'x').limit(1).cap('x')
g.V().aggregate(local, 'x').limit(1).cap('x')
g.withoutStrategies(EarlyLimitStrategy).V().aggregate(local,'x').limit(1).cap('x')

需要注意的是,在 3.3.5 中引入的 EarlyLimitStrategy 改变了 aggregate(local) 的行为。如果没有该策略(默认安装),即使间隔选择为 1 个对象,也会有两个结果在 aggregate() 副作用中,因为第二个对象在传递给 range() 过滤器之前(即 [0..1]),它通过了 aggregate() 并且被存储。

gremlin> g.E().aggregate(local,'x').by('weight').cap('x')
==>[0.5,1.0,1.0,0.4,0.4,0.2]
g.E().aggregate(local,'x').by('weight').cap('x')

其他参考资料

aggregate(String), aggregate(Scope,String)

All 步骤

可以使用 all()-步骤(filter)来过滤列表遍历器。列表中的每个项都会根据提供的谓词进行测试,如果所有项都通过,则遍历器将继续传递,否则将被过滤。空列表会被传递,但 null 或非可迭代遍历器将被过滤掉。

PYTHON 在 Python 中,all 是一个保留字,因此在 Gremlin 中必须使用 all_() 来引用。
gremlin> g.V().values('age').fold().all(gt(25)) //// (1)
==>[29,27,32,35]
g.V().values('age').fold().all(gt(25)) //1
  1. 仅当所有人的年龄都大于 25 岁时,才返回年龄列表。

其他参考资料

all(P), P

And 步骤

and()-步骤确保所有提供的遍历器都产生结果(filter)。有关或语义,请参见 or()

PYTHON 在 Python 中,and 是一个保留字,因此在 Gremlin 中必须使用 and_() 来引用。
gremlin> g.V().and(
            outE('knows'),
            values('age').is(lt(30))).
              values('name')
==>marko
g.V().and(
   outE('knows'),
   values('age').is(lt(30))).
     values('name')

and()-步骤可以接受任意数量的遍历器。只有当所有遍历器都至少产生一个输出时,原始遍历器才会传递到下一步。

也可以使用中缀表示法

gremlin> g.V().where(outE('created').and().outE('knows')).values('name')
==>marko
g.V().where(outE('created').and().outE('knows')).values('name')

其他参考资料

and(Traversal…)

Any 步骤

可以使用 any()-步骤(filter)来过滤列表遍历器。列表中的所有项都将根据提供的谓词进行测试,如果有任何一项通过,则遍历器将继续传递,否则将被过滤。空列表、null 遍历器和非可迭代遍历器也将被过滤掉。

PYTHON 在 Python 中,any 是一个保留字,因此在 Gremlin 中必须使用 any_() 来引用。
gremlin> g.V().values('age').fold().any(gt(25)) //// (1)
==>[29,27,32,35]
g.V().values('age').fold().any(gt(25)) //1
  1. 如果有任何人的年龄大于 25 岁,则返回年龄列表。

其他参考资料

any(P), P

As 步骤

as()-步骤不是一个真正的步骤,而是一个“步骤调节器”,类似于 by()option()。使用 as(),可以为步骤提供一个标签,这个标签可以在后续的步骤和使用这些标签的数据结构中进行访问,例如 select()match() 和 path。

在 Groovy 中,as 是一个保留字,因此在匿名遍历中使用时,在 Gremlin 中必须用双下划线 __.as() 来引用。
PYTHON 在 Python 中,as 是一个保留字,因此在 Gremlin 中必须使用 as_() 来引用。
gremlin> g.V().as('a').out('created').as('b').select('a','b') //// (1)
==>[a:v[1],b:v[3]]
==>[a:v[4],b:v[5]]
==>[a:v[4],b:v[3]]
==>[a:v[6],b:v[3]]
gremlin> g.V().as('a').out('created').as('b').select('a','b').by('name') //// (2)
==>[a:marko,b:lop]
==>[a:josh,b:ripple]
==>[a:josh,b:lop]
==>[a:peter,b:lop]
g.V().as('a').out('created').as('b').select('a','b') //// (1)
g.V().as('a').out('created').as('b').select('a','b').by('name') //2
  1. 从路径中选择标记为 “a” 和 “b” 的对象。
  2. 从路径中选择标记为 “a” 和 “b” 的对象,并对每个对象投影其名称值。

一个步骤可以有任意数量的与之关联的标签。这对于在将来的步骤中多次引用相同的步骤非常有用。

gremlin> g.V().hasLabel('software').as('a','b','c').
            select('a','b','c').
              by('name').
              by('lang').
              by(__.in('created').values('name').fold())
==>[a:lop,b:java,c:[marko,josh,peter]]
==>[a:ripple,b:java,c:[josh]]
g.V().hasLabel('software').as('a','b','c').
   select('a','b','c').
     by('name').
     by('lang').
     by(__.in('created').values('name').fold())

其他参考资料

as(String,String…)

AsString 步骤

asString()-步骤(map)将传入的遍历器的值转换为字符串。空值将保持不变。

gremlin> g.V().hasLabel('person').values('age').asString() //// (1)
==>29
==>27
==>32
==>35
gremlin> g.V().hasLabel('person').values('age').asString().concat(' years old') //// (2)
==>29 years old
==>27 years old
==>32 years old
==>35 years old
gremlin> g.V().hasLabel('person').values('age').fold().asString(local) //// (3)
==>[29,27,32,35]
g.V().hasLabel('person').values('age').asString() //// (1)
g.V().hasLabel('person').values('age').asString().concat(' years old') //// (2)
g.V().hasLabel('person').values('age').fold().asString(local) //3
  1. 将年龄作为字符串返回。
  2. 将年龄作为字符串返回,并使用 concat 生成短语。
  3. 使用 Scope.local 在传入的列表中操作单个字符串元素,这将返回一个列表。

其他参考资料

asString() asString(Scope)

AsDate 步骤

asDate()-步骤(map)将输入的字符串或数值转换为日期。

对于字符串输入,仅支持 ISO-8601 格式。对于数值,该值被视为自 “纪元”(1970 年 1 月 1 日 00:00:00 GMT)以来的毫秒数。日期输入保持不变。

如果传入的遍历器不是字符串、数值或日期,则会抛出 IllegalArgumentException

gremlin> g.inject(1690934400000).asDate() //// (1)
==>Tue Aug 01 17:00:00 PDT 2023
gremlin> g.inject("2023-08-02T00:00:00Z").asDate() //// (2)
==>Tue Aug 01 17:00:00 PDT 2023
gremlin> g.inject(datetime("2023-08-24T00:00:00Z")).asDate() //// (3)
==>Wed Aug 23 17:00:00 PDT 2023
g.inject(1690934400000).asDate() //// (1)
g.inject("2023-08-02T00:00:00Z").asDate() //// (2)
g.inject(datetime("2023-08-24T00:00:00Z")).asDate() //3
  1. 将数字转换为日期
  2. 将 ISO-8601 字符串转换为日期
  3. 不做任何修改地传递日期

Additional References

Barrier Step

barrier()步骤(barrier)将延迟遍历流水线转换为批处理同步流水线。这个步骤在以下情况下非常有用:

  • barrier()之前的所有操作都需要在继续执行barrier()之后的步骤之前执行(即有序性)。
  • 当“暂停”遍历可能导致对重复访问许多相同元素的遍历进行“批量优化”时(即优化)。
gremlin> g.V().sideEffect{println "first: ${it}"}.sideEffect{println "second: ${it}"}.iterate()
first: v[1]
second: v[1]
first: v[2]
second: v[2]
first: v[3]
second: v[3]
first: v[4]
second: v[4]
first: v[5]
second: v[5]
first: v[6]
second: v[6]
gremlin> g.V().sideEffect{println "first: ${it}"}.barrier().sideEffect{println "second: ${it}"}.iterate()
first: v[1]
first: v[2]
first: v[3]
first: v[4]
first: v[5]
first: v[6]
second: v[1]
second: v[2]
second: v[3]
second: v[4]
second: v[5]
second: v[6]
g.V().sideEffect{println "first: ${it}"}.sideEffect{println "second: ${it}"}.iterate()
g.V().sideEffect{println "first: ${it}"}.barrier().sideEffect{println "second: ${it}"}.iterate()

“批量优化”的理论很简单。如果在顶点1有一百万个遍历器,则没有必要计算一百万个both()操作。相反,将这一百万个遍历器表示为一个Traverser.bulk()等于一百万的单个遍历器,并执行一次both()操作。在更大的图中,批量优化示例更加明显。因此,下面的示例利用了Grateful Dead图

gremlin> graph = TinkerGraph.open()
==>tinkergraph[vertices:0 edges:0]
gremlin> g = traversal().withEmbe
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BigDataMLApplication

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值