[关闭]
@contribute 2016-08-29T02:17:02.000000Z 字数 32541 阅读 5496

图的遍历

tinkerpop3

赵亮
weston_contribute@163.com

版权所有
北京太观科技有限公司

摘要



Gremlin 是操作图表的一个非常有用的图灵完备的编程语言。它是一种Java DSL语言,对图表进行查询、分析和操作时使用了大量的XPath。本文对gremlin语言的step进行简单的翻译及解释,也可以参考Tinkerpop的 官方英文文档

在最一般的情况下,遍历就是Traversal<S,E>,它实现了Iterator<E>接口,其中S代表开始,E代表结束。一个遍历由以下四种组件组成:
1. Step<S,E>:将S产生E的一个独立功能。一个遍历有多个step级联组成。
2. TraversalStrategy:改变遍历执行的拦截方法。(例如:查询重写)。
3. TraversalSideEffects:用于存储关于遍历的全局信息的键值对。
4. Traverser<T>:在当前的Traversal中传播的对象,T代表处理的对象。

GraphTraversal<S,E>提供了一个图遍历的经典概念,它继承的Traversal<S,E>。提供了通过点、边等图术语对图数据的解释。

The underlying Step implementations provided by TinkerPop should encompass most of the functionality required by a DSL author. It is important that DSL authors leverage the provided steps as then the common optimization and decoration strategies can reason on the underlying traversal sequence. If new steps are introduced, then common traversal strategies may not function properly.

图遍历步骤

image_1ara020u5er1sipj8352o17sg9.png-119kB
GraphTraversal<S,E>GraphTraversalSource大量产生,也可以由__匿名产生。一个图遍历是由一个有step组成的有序列表构成。

文中的例子使用的图结构关系如下:
tinkerpop-modern.png-175.7kB


AddEdge

推理论证就是将不明确的东西明晰化,在图数据库中明确的东西的就是对象(顶点和边),不明晰的就是遍历。换句话说就是通过遍历定义揭示其中的意义。例如我们拿合作者的概念来说,如果两个人一起参与同一个项目,那么这两个人就是合作者。这个概念可以用遍历来描述。而且不明晰的关系可以通过addE()来明晰化。
addedge-step.png-166.5kB

  1. gremlin> g.V(1).as('a').out('created').in('created').where(neq('a')).
  2. addE('co-developer').from('a').property('year',2009) //(1)
  3. ==>e[12][1-co-developer->4]
  4. ==>e[13][1-co-developer->6]
  5. gremlin> g.V(3,4,5).aggregate('x').has('name','josh').as('a').
  6. select('x').unfold().hasLabel('software').addE('createdBy').to('a') //(2)
  7. ==>e[14][3-createdBy->4]
  8. ==>e[15][5-createdBy->4]
  9. gremlin> g.V().as('a').out('created').addE('createdBy').to('a').property('acl','public') //(3)
  10. ==>e[16][3-createdBy->1]
  11. ==>e[17][5-createdBy->4]
  12. ==>e[18][3-createdBy->4]
  13. ==>e[19][3-createdBy->6]
  14. gremlin> g.V(1).as('a').out('knows').
  15. addE('livesNear').from('a').property('year',2009).
  16. inV().inE('livesNear').values('year') //(4)
  17. ==>2009
  18. ==>2009
  19. gremlin> g.V().match(
  20. __.as('a').out('knows').as('b'),
  21. __.as('a').out('created').as('c'),
  22. __.as('b').out('created').as('c')).
  23. addE('friendlyCollaborator').from('a').to('b').
  24. property(id,13).property('project',select('c').values('name')) //(5)
  25. ==>e[13][1-friendlyCollaborator->4]
  26. gremlin> g.E(13).valueMap()
  27. ==>[project:lop]

AddVertex

  1. #添加一个类型为person的顶点
  2. g.addV('person').property('name','stephen')
  1. # 在边上添加一个顶点()
  2. g.V().outE('knows').addV().property('name','nothing')

查询了g.V(14).valueMap()并没有看到属性name=nothing。

AddProperty

在顶点上添加一个属性

  1. gremlin> g.V(1).property('country','usa')
  2. ==>v[1]

在顶点上添加多个属性

  1. gremlin> g.V(1).property('city','santa fe').property('state','new mexico').valueMap()
  2. ==>[country:[usa], city:[santa fe], name:[marko], state:[new mexico], age:[29]]

在顶点上的一个属性添加多个值

  1. gremlin> g.V(1).property(list,'age',35) //(1)
  2. ==>v[1]
  3. gremlin> g.V(1).valueMap()
  4. ==>[country:[usa], city:[santa fe], name:[marko], state:[new mexico], age:[29, 35]]

为顶点上的一个属性添加私有的访问控制权限

  1. gremlin> g.V(1).property('friendWeight',outE('knows').values('weight').sum(),'acl','private') //(2)
  2. ==>v[1]
  3. gremlin> g.V(1).properties('friendWeight').valueMap() //(3)
  4. ==>[acl:private]

其中outE('knows').values('weight').sum()表示图中所有边的属性weight值的总和。

Aggregate

aggregate-step.png-95.1kB

aggregate()被用于将某个step后的结果聚合为一个collection。这里使用了eager evaluation的概念,在某个特殊点的结果需要参与未来某个计算时eager evaluation显得尤为重要。通俗的说,在某个step之后使用了aggregate函数时,将此结果(collection)保存起来并命名(例如x),以便后续step的使用,如搭配(without('x')等函数使用)。举个例子:

  1. gremlin> g.V(1).out('created') //marko创建什么
  2. ==>v[3]
  3. gremlin> g.V(1).out('created').aggregate('x') //将他创造的东西聚合起来
  4. ==>v[3]
  5. gremlin> g.V(1).out('created').aggregate('x').in('created') // 谁是marko的合作者
  6. ==>v[1]
  7. ==>v[4]
  8. ==>v[6]
  9. gremlin> g.V(1).out('created').aggregate('x').in('created').out('created') //他的合作者创建了什么
  10. ==>v[3]
  11. ==>v[5]
  12. ==>v[3]
  13. ==>v[3]
  14. gremlin> g.V(1).out('created').aggregate('x').in('created').out('created').
  15. where(without('x')).values('name') //(5)他的合作者所创建的东西哪些marko没有参与
  16. ==>ripple

Finally, aggregate()可以通过by()调整并映射出结果。

  1. gremlin> g.V().out('knows').aggregate('x').cap('x')
  2. ==>{v[2]=1, v[4]=1}
  3. gremlin> g.V().out('knows').aggregate('x').by('name').cap('x')
  4. ==>{vadas=1, josh=1}

And

‘与’操作,跟java中的‘&&’类似。

  1. gremlin> g.V().and(
  2. outE('knows'),
  3. values('age').is(lt(30))).
  4. values('name')
  5. ==>marko

and()能做任意变量的遍历。但是所有的遍历必须产生至少一个输出传给后续步骤。

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

As

其实As()不能真正意义上的step,而是一个步骤调节器,类似by()option()。为一个step(后续步骤)或数据结构(后续产生的结构)提供标签。

  1. gremlin> g.V().as('a').out('created').as('b').select('a','b') //(1)
  2. ==>[a:v[1], b:v[3]]
  3. ==>[a:v[4], b:v[5]]
  4. ==>[a:v[4], b:v[3]]
  5. ==>[a:v[6], b:v[3]]
  6. gremlin> g.V().as('a').out('created').as('b').select('a','b').by('name') //(2)
  7. ==>[a:marko, b:lop]
  8. ==>[a:josh, b:ripple]
  9. ==>[a:josh, b:lop]
  10. ==>[a:peter, b:lop]

可以为结果提供多个标签,针对这个集合做不同的处理。如下:

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

Barrier

barrier()将将延迟遍历管道(lazy traversal pipeline)转化为容量同步(bulk-synchronous)的管道。barrier()用于以下两种情况:
1. 在barrier()之前的先执行,然后再执行barrier()后面的,在一个iterator()中也是如此。
2. 重复操作一个结果集时使用这个停顿能优化计算。

  1. gremlin> g.V().sideEffect{println "first: ${it}"}.sideEffect{println "second: ${it}"}.iterate()
  2. first: v[1]
  3. second: v[1]
  4. first: v[2]
  5. second: v[2]
  6. first: v[3]
  7. second: v[3]
  8. first: v[4]
  9. second: v[4]
  10. first: v[5]
  11. second: v[5]
  12. first: v[6]
  13. second: v[6]
  14. gremlin> g.V().sideEffect{println "first: ${it}"}.barrier().sideEffect{println "second: ${it}"}.iterate()
  15. first: v[1]
  16. first: v[2]
  17. first: v[3]
  18. first: v[4]
  19. first: v[5]
  20. first: v[6]
  21. second: v[1]
  22. second: v[2]
  23. second: v[3]
  24. second: v[4]
  25. second: v[5]
  26. second: v[6]

By

by()不是一个真正的step,而是一个step-modulator,与as()option()类似。其通用的使用模式为step().by()...by()

  1. gremlin> g.V().group().by(bothE().count()) //(1)
  2. ==>[1:[v[2], v[5], v[6]], 3:[v[1], v[3], v[4]]]
  3. gremlin> g.V().group().by(bothE().count()).by('name') //(2)
  4. ==>[1:[vadas, ripple, peter], 3:[marko, lop, josh]]
  5. gremlin> g.V().group().by(bothE().count()).by(count()) //(3)
  6. ==>[1:3, 3:3]

Cap

The cap()-step (barrier) iterates the traversal up to itself and emits the sideEffect referenced by the provided key. If multiple keys are provided, then a Map of sideEffects is emitted.

  1. gremlin> g.V().groupCount('a').by(label).cap('a') //(1)
  2. ==>[software:2, person:4]
  3. gremlin> g.V().groupCount('a').by(label).groupCount('b').by(outE().count()).cap('a','b') //(2)
  4. ==>[a:[software:2, person:4], b:[0:3, 1:1, 2:1, 3:1]]

Coalesce

coalesce()就是将提供的遍历器顺序执行,如果第一个有值,则返回,否则找第二个,直到有值返回。

  1. gremlin> g.V(1).coalesce(outE('knows'), outE('created')).inV().path().by('name').by(label)
  2. ==>[marko, knows, vadas]
  3. ==>[marko, knows, josh]
  4. gremlin> g.V(1).coalesce(outE('created'), outE('knows')).inV().path().by('name').by(label)
  5. ==>[marko, created, lop]
  6. gremlin> g.V(1).property('nickname', 'okram')
  7. ==>v[1]
  8. gremlin> g.V().hasLabel('person').coalesce(values('nickname'), values('name'))
  9. ==>okram
  10. ==>vadas
  11. ==>josh
  12. ==>peter

Count

计算遍历结果的总量。

  1. gremlin> g.V().count()
  2. ==>6
  3. gremlin> g.V().hasLabel('person').count()
  4. ==>4
  5. gremlin> g.V().hasLabel('person').outE('created').count().path() //(1)
  6. ==>[4]
  7. gremlin> g.V().hasLabel('person').outE('created').count().map {it.get() * 10}.path() //(2)
  8. ==>[4, 40]

Choose

由当前遍历器到一个特殊的遍历器的分支操作,它能实现基于if/else语义甚至更为复杂的语义。
choose-step.png-115.8kB

  1. gremlin> g.V().hasLabel('person').
  2. choose(values('age').is(lte(30)),
  3. __.in(),
  4. __.out()).values('name') //如果遍历产生了一个元素,那么做in,否则做out(基于true/false的选择器)
  5. ==>marko
  6. ==>ripple
  7. ==>lop
  8. ==>lop
  9. gremlin> g.V().hasLabel('person').
  10. choose(values('age')).
  11. option(27, __.in()).
  12. option(32, __.out()).values('name') //将遍历的结果集作为遍历选择器map的key。
  13. ==>marko
  14. ==>ripple
  15. ==>lop

然而,choose()也能实现类似switch的功能。

  1. gremlin> g.V().hasLabel('person').
  2. choose(values('name')).
  3. option('marko', values('age')).
  4. option('josh', values('name')).
  5. option('vadas', valueMap()).
  6. option('peter', label())
  7. ==>29
  8. ==>[name:[vadas], age:[27]]
  9. ==>josh
  10. ==>person

choose()还能利用Pick.none选项来匹配。不能匹配的选项,这时none就起作用了。

  1. gremlin> g.V().hasLabel('person').
  2. choose(values('name')).
  3. option('marko', values('age')).
  4. option(none, values('name'))
  5. ==>29
  6. ==>vadas
  7. ==>josh
  8. ==>peter

Coin

一个随机过滤的遍历器,提供了一个浮点参数的偏差值

  1. gremlin> g.V().coin(0.5)
  2. ==>v[1]
  3. ==>v[3]
  4. ==>v[4]
  5. ==>v[5]
  6. gremlin> g.V().coin(0.0)
  7. gremlin> g.V().coin(1.0)
  8. ==>v[1]
  9. ==>v[2]
  10. ==>v[3]
  11. ==>v[4]
  12. ==>v[5]
  13. ==>v[6]

Constant

为某个遍历器指定一个常量值,这个配合基于条件的步骤如choose()coalesce()

  1. gremlin> g.V().choose(hasLabel('person'),
  2. values('name'),
  3. constant('inhuman')) //(1)
  4. ==>marko
  5. ==>vadas
  6. ==>inhuman
  7. ==>josh
  8. ==>inhuman
  9. ==>peter
  10. gremlin> g.V().coalesce(
  11. hasLabel('person').values('name'),
  12. constant('inhuman')) //显示人名,如果不是人,则显示'inhuman'
  13. ==>marko
  14. ==>vadas
  15. ==>inhuman
  16. ==>josh
  17. ==>inhuman
  18. ==>peter

CyclicPath

cyclicpath-step.png-130.5kB
每个遍历器在图中遍历时都有其轨迹,也就是path()。在遍历的过程中有可能重复其轨迹,这是cyclicPath()就能用到。如果想过滤遍历过程中重复的路径,就是说不希望重复其路径,则可以使用simplePath()

  1. gremlin> g.V(1).both().both()
  2. ==>v[1]
  3. ==>v[4]
  4. ==>v[6]
  5. ==>v[1]
  6. ==>v[5]
  7. ==>v[3]
  8. ==>v[1]
  9. gremlin> g.V(1).both().both().cyclicPath()
  10. ==>v[1]
  11. ==>v[1]
  12. ==>v[1]
  13. gremlin> g.V(1).both().both().cyclicPath().path()
  14. ==>[v[1], v[3], v[1]]
  15. ==>[v[1], v[2], v[1]]
  16. ==>[v[1], v[4], v[1]]

Dedup

dedup()用于对结果集去重。

  1. gremlin> g.V().values('lang')
  2. ==>java
  3. ==>java
  4. gremlin> g.V().values('lang').dedup()
  5. ==>java
  6. gremlin> g.V(1).repeat(bothE('created').dedup().otherV()).emit().path() //(1)
  7. ==>[v[1], e[9][1-created->3], v[3]]
  8. ==>[v[1], e[9][1-created->3], v[3], e[11][4-created->3], v[4]]
  9. ==>[v[1], e[9][1-created->3], v[3], e[12][6-created->3], v[6]]
  10. ==>[v[1], e[9][1-created->3], v[3], e[11][4-created->3], v[4], e[10][4-created->5], v[5]]

dedup()也可以配合by()来使用:

  1. gremlin> g.V().valueMap(true, 'name')
  2. ==>[label:person, name:[marko], id:1]
  3. ==>[label:person, name:[vadas], id:2]
  4. ==>[label:software, name:[lop], id:3]
  5. ==>[label:person, name:[josh], id:4]
  6. ==>[label:software, name:[ripple], id:5]
  7. ==>[label:person, name:[peter], id:6]
  8. gremlin> g.V().dedup().by(label).values('name')
  9. ==>marko
  10. ==>lop

Finally, if dedup() is provided an array of strings, then it will ensure that the de-duplication is not with respect to the current traverser object, but to the path history of the traverser.

  1. gremlin> g.V().as('a').out('created').as('b').in('created').as('c').select('a','b','c')
  2. ==>[a:v[1], b:v[3], c:v[1]]
  3. ==>[a:v[1], b:v[3], c:v[4]]
  4. ==>[a:v[1], b:v[3], c:v[6]]
  5. ==>[a:v[4], b:v[5], c:v[4]]
  6. ==>[a:v[4], b:v[3], c:v[1]]
  7. ==>[a:v[4], b:v[3], c:v[4]]
  8. ==>[a:v[4], b:v[3], c:v[6]]
  9. ==>[a:v[6], b:v[3], c:v[1]]
  10. ==>[a:v[6], b:v[3], c:v[4]]
  11. ==>[a:v[6], b:v[3], c:v[6]]
  12. gremlin> g.V().as('a').out('created').as('b').in('created').as('c').dedup('a','b').select('a','b','c') //(1)
  13. ==>[a:v[1], b:v[3], c:v[1]]
  14. ==>[a:v[4], b:v[5], c:v[4]]
  15. ==>[a:v[4], b:v[3], c:v[1]]
  16. ==>[a:v[6], b:v[3], c:v[1]]

Drop

drop()用于删除图中的元素(点和边)或属性:

  1. gremlin> g.V().outE().drop()
  2. gremlin> g.E()
  3. gremlin> g.V().properties('name').drop()
  4. gremlin> g.V().valueMap()
  5. ==>[age:[29]]
  6. ==>[age:[27]]
  7. ==>[lang:[java]]
  8. ==>[age:[32]]
  9. ==>[lang:[java]]
  10. ==>[age:[35]]
  11. gremlin> g.V().drop()
  12. gremlin> g.V()

Explain

The explain()-step (sideEffect) will return a TraversalExplanation. A traversal explanation details how the traversal (prior to explain()) will be compiled given the registered traversal strategies. A TraversalExplanation has a toString() representation with 3-columns. The first column is the traversal strategy being applied. The second column is the traversal strategy category: [D]ecoration, [O]ptimization, [P]rovider optimization, [F]inalization, and [V]erification. Finally, the third column is the state of the traversal post strategy application. The final traversal is the resultant execution plan.

  1. gremlin> g.V().hasLabel('person').outE().identity().inV().count().is(gt(5)).explain()
  2. ==>Traversal Explanation
  3. ===============================================================================================================================================================================
  4. Original Traversal [GraphStep([],vertex), HasStep([~label.eq(person)]), VertexStep(OUT,edge), IdentityStep, EdgeVertexStep(IN), CountGlobalStep, IsStep(gt(5))]
  5. ConnectiveStrategy [D] [GraphStep([],vertex), HasStep([~label.eq(person)]), VertexStep(OUT,edge), IdentityStep, EdgeVertexStep(IN), CountGlobalStep, IsStep(gt(5))]
  6. IdentityRemovalStrategy [O] [GraphStep([],vertex), HasStep([~label.eq(person)]), VertexStep(OUT,edge), EdgeVertexStep(IN), CountGlobalStep, IsStep(gt(5))]
  7. IncidentToAdjacentStrategy [O] [GraphStep([],vertex), HasStep([~label.eq(person)]), VertexStep(OUT,vertex), CountGlobalStep, IsStep(gt(5))]
  8. AdjacentToIncidentStrategy [O] [GraphStep([],vertex), HasStep([~label.eq(person)]), VertexStep(OUT,edge), CountGlobalStep, IsStep(gt(5))]
  9. FilterRankingStrategy [O] [GraphStep([],vertex), HasStep([~label.eq(person)]), VertexStep(OUT,edge), CountGlobalStep, IsStep(gt(5))]
  10. MatchPredicateStrategy [O] [GraphStep([],vertex), HasStep([~label.eq(person)]), VertexStep(OUT,edge), CountGlobalStep, IsStep(gt(5))]
  11. RangeByIsCountStrategy [O] [GraphStep([],vertex), HasStep([~label.eq(person)]), VertexStep(OUT,edge), RangeGlobalStep(0,6), CountGlobalStep, IsStep(gt(5))]
  12. TinkerGraphStepStrategy [P] [TinkerGraphStep(vertex,[~label.eq(person)]), VertexStep(OUT,edge), RangeGlobalStep(0,6), CountGlobalStep, IsStep(gt(5))]
  13. EngineDependentStrategy [F] [TinkerGraphStep(vertex,[~label.eq(person)]), VertexStep(OUT,edge), RangeGlobalStep(0,6), CountGlobalStep, IsStep(gt(5))]
  14. ProfileStrategy [F] [TinkerGraphStep(vertex,[~label.eq(person)]), VertexStep(OUT,edge), RangeGlobalStep(0,6), CountGlobalStep, IsStep(gt(5))]
  15. StandardVerificationStrategy [V] [TinkerGraphStep(vertex,[~label.eq(person)]), VertexStep(OUT,edge), RangeGlobalStep(0,6), CountGlobalStep, IsStep(gt(5))]
  16. ComputerVerificationStrategy [V] [TinkerGraphStep(vertex,[~label.eq(person)]), VertexStep(OUT,edge), RangeGlobalStep(0,6), CountGlobalStep, IsStep(gt(5))]
  17. Final Traversal [TinkerGraphStep(vertex,[~label.eq(person)]), VertexStep(OUT,edge), RangeGlobalStep(0,6), CountGlobalStep, IsStep(gt(5))]

Fold

当遍历流需要一个“界限”来聚合所有对象时就会用到fold(),可以用unfold()进行反向操作。

  1. gremlin> g.V(1).out('knows').values('name')
  2. ==>vadas
  3. ==>josh
  4. gremlin> g.V(1).out('knows').values('name').fold() //聚合所有的对象为一个list
  5. ==>[vadas, josh]
  6. gremlin> g.V(1).out('knows').values('name').fold().next().getClass() //可以看到这是一个list
  7. ==>class java.util.ArrayList
  8. gremlin> g.V(1).out('knows').values('name').fold(0) {a,b -> a + b.length()} //(3)
  9. ==>9
  10. gremlin> g.V().values('age').fold(0) {a,b -> a + b} //(4)
  11. ==>123
  12. gremlin> g.V().values('age').fold(0, sum) //整个图中所有年龄的总和。
  13. ==>123
  14. gremlin> g.V().values('age').sum() //(6)
  15. ==>123

Group

group()配合by()使用,类似与sql语言中的group by()

  1. gremlin> g.V().group().by(label) //(1)
  2. ==>[software:[v[3], v[5]], person:[v[1], v[2], v[4], v[6]]]
  3. gremlin> g.V().group().by(label).by('name') //(2)
  4. ==>[software:[lop, ripple], person:[marko, vadas, josh, peter]]
  5. gremlin> g.V().group().by(label).by(count()) //(3)
  6. ==>[software:2, person:4]

GroupCount

当某个遍历的过程中,想知道一个特别对象出现的次数,则用到groupCount()

  1. gremlin> g.V().hasLabel('person').values('age').groupCount()
  2. ==>[32:1, 35:1, 27:1, 29:1]
  3. gremlin> g.V().hasLabel('person').groupCount().by('age') //(1)
  4. ==>[32:1, 35:1, 27:1, 29:1]

Has

has-step.png-91.5kB
has()用于过滤点、边以及属性。这里有多个变种:
1. has(key,value):如果遍历器中没有提供的key/value属性时,过滤掉。
2. has(key,predicate):过滤掉元素中不提供这个值或提供的值不满足后面的判断条件。
3. hasLabel(labels...):过滤没有这个标签的。
4. hasId(ids...):过滤没有这些标签的元素。
5. hasKey(keys...):过滤没有这些没有这个key属性遍历器。
6. hasValue(values...):删除属性中没有这些值的遍历器。
7. has(key):过滤元素中没有这些值的遍历器
8. hasNot(key):过滤元素中有这些值遍历器
9. has(key, traversal):

  1. gremlin> g.V().hasLabel('person')
  2. ==>v[1]
  3. ==>v[2]
  4. ==>v[4]
  5. ==>v[6]
  6. gremlin> g.V().hasLabel('person').out().has('name',within('vadas','josh'))
  7. ==>v[2]
  8. ==>v[4]
  9. gremlin> g.V().hasLabel('person').out().has('name',within('vadas','josh')).
  10. outE().hasLabel('created')
  11. ==>e[10][4-created->5]
  12. ==>e[11][4-created->3]
  13. gremlin> g.V().has('age',inside(20,30)).values('age') //找出所有年龄在[20-30)之间的顶点。
  14. ==>29
  15. ==>27
  16. gremlin> g.V().has('age',outside(20,30)).values('age') //找出所有年龄不在[20-30)之间的顶点。
  17. ==>32
  18. ==>35
  19. gremlin> g.V().has('name',within('josh','marko')).valueMap() //找出名字为josh或marko的属性。
  20. ==>[name:[marko], age:[29]]
  21. ==>[name:[josh], age:[32]]
  22. gremlin> g.V().has('name',without('josh','marko')).valueMap() //找出名字不为josh和marko的属性。
  23. ==>[name:[vadas], age:[27]]
  24. ==>[name:[lop], lang:[java]]
  25. ==>[name:[ripple], lang:[java]]
  26. ==>[name:[peter], age:[35]]
  27. gremlin> g.V().has('name',not(within('josh','marko'))).valueMap() //找出名字不为josh和marko的属性。
  28. ==>[name:[vadas], age:[27]]
  29. ==>[name:[lop], lang:[java]]
  30. ==>[name:[ripple], lang:[java]]
  31. ==>[name:[peter], age:[35]]

Inject

inject-step.png-70.5kB
Tinkerpop3一个主要的特征是jnject()。这就可以让我们任意的在遍历流中注入对象。

  1. gremlin> g.V(4).out().values('name').inject('daniel')
  2. ==>daniel
  3. ==>ripple
  4. ==>lop
  5. gremlin> g.V(4).out().values('name').inject('daniel').map {it.get().length()}
  6. ==>6
  7. ==>6
  8. ==>3
  9. gremlin> g.V(4).out().values('name').inject('daniel').map {it.get().length()}.path()
  10. ==>[daniel, 6]
  11. ==>[v[4], v[5], ripple, 6]
  12. ==>[v[4], v[3], lop, 3]

如果开始的不是一个图中的对象(顶点和边),inject()也可以这样用:

  1. gremlin> inject(1,2)
  2. ==>1
  3. ==>2
  4. gremlin> inject(1,2).map {it.get() + 1}
  5. ==>2
  6. ==>3
  7. gremlin> inject(1,2).map {it.get() + 1}.map {g.V(it.get()).next()}.values('name')
  8. ==>vadas
  9. ==>lop

Is

is()用于过滤数量值。

  1. gremlin> g.V().values('age').is(32)
  2. ==>32
  3. gremlin> g.V().values('age').is(lte(30))
  4. ==>29
  5. ==>27
  6. gremlin> g.V().values('age').is(inside(30, 40))
  7. ==>32
  8. ==>35
  9. gremlin> g.V().where(__.in('created').count().is(1)).values('name') //(1)
  10. ==>ripple
  11. gremlin> g.V().where(__.in('created').count().is(gte(2))).values('name') //(2)
  12. ==>lop
  13. gremlin> g.V().where(__.in('created').values('age').
  14. mean().is(inside(30d, 35d))).values('name') //(3)
  15. ==>lop
  16. ==>ripple

Limit

limit()range()的功能类似,从1开始计数。

  1. gremlin> g.V().limit(2)
  2. ==>v[1]
  3. ==>v[2]
  4. gremlin> g.V().range(0, 2)
  5. ==>v[1]
  6. ==>v[2]
  7. gremlin> g.V().limit(2).toString()
  8. ==>[GraphStep([],vertex), RangeGlobalStep(0,2)]

Local

local-step.png-93.4kB

Match

match()提供一种基于模式匹配概念的图查询的声明形式。使用它,用户提供了遍历片段的集合,这些定义的遍历片段在match过程中必须返回true值。

"Who created a project named 'lop' that was also created by someone who is 29 years old? Return the two creators."

match-step.png-178.4kB

  1. gremlin> g.V().match(
  2. __.as('a').out('created').as('b'),
  3. __.as('b').has('name', 'lop'),
  4. __.as('b').in('created').as('c'),
  5. __.as('c').has('age', 29)).
  6. select('a','c').by('name')
  7. ==>[a:marko, c:marko]
  8. ==>[a:josh, c:marko]
  9. ==>[a:peter, c:marko]

使用where()与其配合使用

  1. gremlin> g.V().match(
  2. __.as('a').out('created').as('b'),
  3. __.as('b').in('created').as('c')).
  4. where('a', neq('c')).
  5. select('a','c').by('name')
  6. ==>[a:marko, c:josh]
  7. ==>[a:marko, c:peter]
  8. ==>[a:josh, c:marko]
  9. ==>[a:josh, c:peter]
  10. ==>[a:peter, c:marko]
  11. ==>[a:peter, c:josh]

Max

找出结果集中最大的数

  1. gremlin> g.V().values('age').max()
  2. ==>35
  3. gremlin> g.V().repeat(both()).times(3).values('age').max()
  4. ==>35

注意:max(local)检测的是当前本地的最大值(而不是遍历结果集中的值),操作的对象为CollectionNumber类型的对象。操作其他对象就会返回Double.NaN

Mean

mean()求平均值

  1. gremlin> g.V().values('age').mean()
  2. ==>30.75
  3. gremlin> g.V().repeat(both()).times(3).values('age').mean() //(1)
  4. ==>30.645833333333332
  5. gremlin> g.V().repeat(both()).times(3).values('age').dedup().mean()
  6. ==>30.75

Min

求最小值

  1. gremlin> g.V().values('age').min()
  2. ==>27
  3. gremlin> g.V().repeat(both()).times(3).values('age').min()
  4. ==>27

Or

相当与一个操作,可以参考and()方法

  1. gremlin> g.V().or(
  2. __.outE('created'),
  3. __.inE('created').count().is(gt(1))).
  4. values('name')
  5. ==>marko
  6. ==>lop
  7. ==>josh
  8. ==>peter

Order

对结果集进行排序

  1. gremlin> g.V().values('name').order()
  2. ==>josh
  3. ==>lop
  4. ==>marko
  5. ==>peter
  6. ==>ripple
  7. ==>vadas
  8. gremlin> g.V().values('name').order().by(decr)
  9. ==>vadas
  10. ==>ripple
  11. ==>peter
  12. ==>marko
  13. ==>lop
  14. ==>josh
  15. gremlin> g.V().hasLabel('person').order().by('age', incr).values('name')
  16. ==>vadas
  17. ==>marko
  18. ==>josh
  19. ==>peter

遍历器遍历的结果集大部分都是元素,而元素都有相关属性与之关联,在很多情况下,很多情况下,都需要对元素的属性进行排序。如下:

  1. gremlin> g.V().values('name')
  2. ==>marko
  3. ==>vadas
  4. ==>lop
  5. ==>josh
  6. ==>ripple
  7. ==>peter
  8. gremlin> g.V().order().by('name',incr).values('name')
  9. ==>josh
  10. ==>lop
  11. ==>marko
  12. ==>peter
  13. ==>ripple
  14. ==>vadas
  15. gremlin> g.V().order().by('name',decr).values('name')
  16. ==>vadas
  17. ==>ripple
  18. ==>peter
  19. ==>marko
  20. ==>lop
  21. ==>josh

Path

一个遍历器的遍历被转化为多个遍历的step的顺序执行,那么遍历路径可以通过path()来显示执行的路径。如下图:
path-step.png-180kB

举例:

  1. gremlin> g.V().out().out().values('name')
  2. ==>ripple
  3. ==>lop
  4. gremlin> g.V().out().out().values('name').path()
  5. ==>[v[1], v[4], v[5], ripple]
  6. ==>[v[1], v[4], v[3], lop]

如果希望边显示路径,那么需确保明确的遍历这些边:

  1. gremlin> g.V().outE().inV().outE().inV().path()
  2. ==>[v[1], e[8][1-knows->4], v[4], e[10][4-created->5], v[5]]
  3. ==>[v[1], e[8][1-knows->4], v[4], e[11][4-created->3], v[3]]

如果以循环的方式遍历这些元素的路径可以通过path()搭配by()使用:

  1. gremlin> g.V().out().out().path().by('name').by('age')
  2. ==>[marko, 32, ripple]
  3. ==>[marko, 32, lop]

Path的数据结构

path的数据结构是一个有序的对象列表,每个对象对应Set集合标签。举个例子:
path-data-structure.png-25.3kB

  1. gremlin> path = g.V(1).as('a').has('name').as('b').
  2. out('knows').out('created').as('c').
  3. has('name','ripple').values('name').as('d').
  4. identity().as('e').path().next()
  5. ==>v[1]
  6. ==>v[4]
  7. ==>v[5]
  8. ==>ripple
  9. gremlin> path.size()
  10. ==>4
  11. gremlin> path.objects()
  12. ==>v[1]
  13. ==>v[4]
  14. ==>v[5]
  15. ==>ripple
  16. gremlin> path.labels()
  17. ==>[a, b]
  18. ==>[]
  19. ==>[c]
  20. ==>[d, e]
  21. gremlin> path.a
  22. ==>v[1]
  23. gremlin> path.b
  24. ==>v[1]
  25. gremlin> path.c
  26. ==>v[5]
  27. gremlin> path.d == path.e
  28. ==>true

Profile

The profile()-step (sideEffect) exists to allow developers to profile their traversals to determine statistical information like step runtime, counts, etc.

Range

当遍历器在遍历的过程中,只能允许结果集中的一定数量的结果参与后续的处理,这时可以使用profile()。如果结果集中小于最小范围时,则继续迭代;如果在range的范围内,则可以参与后续操作;如果大于最大范围,则停止。如下:

  1. gremlin> g.V().range(0,3)
  2. ==>v[1]
  3. ==>v[2]
  4. ==>v[3]
  5. gremlin> g.V().range(1,3)
  6. ==>v[2]
  7. ==>v[3]
  8. gremlin> g.V().repeat(both()).times(1000000).emit().range(6,10)
  9. ==>v[1]
  10. ==>v[5]
  11. ==>v[3]
  12. ==>v[1]

当操作一个集合时,range()可以与Scope.local使用。

  1. gremlin> g.V().as('a').out().as('b').in().as('c').select('a','b','c').by('name').range(local,1,2)
  2. ==>[b:lop]
  3. ==>[b:lop]
  4. ==>[b:lop]
  5. ==>[b:vadas]
  6. ==>[b:josh]
  7. ==>[b:ripple]
  8. ==>[b:lop]
  9. ==>[b:lop]
  10. ==>[b:lop]
  11. ==>[b:lop]
  12. ==>[b:lop]
  13. ==>[b:lop]

Repeat

repeat()被用于循环执行给定执行语句或step。

  1. gremlin> g.V(1).repeat(out()).times(2).path().by('name') //与out()方法配合,实现do-while语法
  2. ==>[marko, josh, ripple]
  3. ==>[marko, josh, lop]
  4. gremlin> g.V().until(has('name','ripple')).
  5. repeat(out()).path().by('name') //while-do语法。
  6. ==>[marko, josh, ripple]
  7. ==>[josh, ripple]
  8. ==>[ripple]

重点:针对repeat()配合使用的两个step:until()emit()。如果repeat()until()的前面,则实现do/while循环;如果repeat()出现在until()后面,则实现while/do循环。如果emit()出现在repeat()后面,则处理repeat()之后的结果集;如果emit()出现在repeat()前面,则优先处理repeat()之前的结果集。

  1. gremlin> g.V(1).repeat(out()).times(2).emit().path().by('name') //(1)
  2. ==>[marko, lop]
  3. ==>[marko, vadas]
  4. ==>[marko, josh]
  5. ==>[marko, josh, ripple]
  6. ==>[marko, josh, lop]
  7. gremlin> g.V(1).emit().repeat(out()).times(2).path().by('name') //(2)
  8. ==>[marko]
  9. ==>[marko, lop]
  10. ==>[marko, vadas]
  11. ==>[marko, josh]
  12. ==>[marko, josh, ripple]
  13. ==>[marko, josh, lop]

Sack

Sample

sample()用于对结果集进行抽样。

  1. gremlin> g.V().outE().sample(1).values('weight')
  2. ==>0.5
  3. gremlin> g.V().outE().sample(1).by('weight').values('weight')
  4. ==>1.0
  5. gremlin> g.V().outE().sample(2).by('weight').values('weight')
  6. ==>1.0
  7. ==>0.4

sample()一个最有趣的使用案例是与local()配合使用。这种配合使用支持 random walks 的执行。

  1. gremlin> g.V(1).repeat(local(
  2. bothE().sample(1).by('weight').otherV()
  3. )).times(5)
  4. ==>v[2]
  5. gremlin> g.V(1).repeat(local(
  6. bothE().sample(1).by('weight').otherV()
  7. )).times(5).path()
  8. ==>[v[1], e[8][1-knows->4], v[4], e[11][4-created->3], v[3], e[9][1-created->3], v[1], e[8][1-knows->4], v[4], e[8][1-knows->4], v[1]]
  9. gremlin> g.V(1).repeat(local(
  10. bothE().sample(1).by('weight').otherV()
  11. )).times(10).path()
  12. ==>[v[1], e[8][1-knows->4], v[4], e[8][1-knows->4], v[1], e[9][1-created->3], v[3], e[11][4-created->3], v[4], e[10][4-created->5], v[5], e[10][4-created->5], v[4], e[10][4-created->5], v[5], e[10][4-created->5], v[4], e[10][4-created->5], v[5], e[10][4-created->5], v[4]]

Select

函数式语言利用函数组合和惰性计算能创建复杂的计算。这正是Traversal所做的事情。gremlin数据流一个小区分就是数据流不一直是向前流动,事实上而是可能回到之间的数据集计算。这样的例子包括path()select()。有两种使用select()方式:
1. 在路径中选择标签steps。
2. 从Map中选择结果。

  1. gremlin> g.V().as('a').out().as('b').out().as('c') // no select
  2. ==>v[5]
  3. ==>v[3]
  4. gremlin> g.V().as('a').out().as('b').out().as('c').select('a','b','c')
  5. ==>[a:v[1], b:v[4], c:v[5]]
  6. ==>[a:v[1], b:v[4], c:v[3]]
  7. gremlin> g.V().as('a').out().as('b').out().as('c').select('a','b')
  8. ==>[a:v[1], b:v[4]]
  9. ==>[a:v[1], b:v[4]]
  10. gremlin> g.V().as('a').out().as('b').out().as('c').select('a','b').by('name')
  11. ==>[a:marko, b:josh]
  12. ==>[a:marko, b:josh]
  13. gremlin> g.V().as('a').out().as('b').out().as('c').select('a') //(1)
  14. ==>v[1]
  15. ==>v[1]

配合where使用

  1. gremlin> g.V().as('a').out('created').in('created').as('b').select('a','b').by('name') //(1)
  2. ==>[a:marko, b:marko]
  3. ==>[a:marko, b:josh]
  4. ==>[a:marko, b:peter]
  5. ==>[a:josh, b:josh]
  6. ==>[a:josh, b:marko]
  7. ==>[a:josh, b:josh]
  8. ==>[a:josh, b:peter]
  9. ==>[a:peter, b:marko]
  10. ==>[a:peter, b:josh]
  11. ==>[a:peter, b:peter]
  12. gremlin> g.V().as('a').out('created').in('created').as('b').
  13. select('a','b').by('name').where('a',neq('b')) //(2)
  14. ==>[a:marko, b:josh]
  15. ==>[a:marko, b:peter]
  16. ==>[a:josh, b:marko]
  17. ==>[a:josh, b:peter]
  18. ==>[a:peter, b:marko]
  19. ==>[a:peter, b:josh]
  20. gremlin> g.V().as('a').out('created').in('created').as('b').
  21. select('a','b'). //(3)
  22. where('a',neq('b')).
  23. where(__.as('a').out('knows').as('b')).
  24. select('a','b').by('name')
  25. ==>[a:marko, b:josh]

SimplePath

simplePath()用于过滤重复的路径,可以参考path()cyclicPath()

  1. gremlin> g.V(1).both().both()
  2. ==>v[1]
  3. ==>v[4]
  4. ==>v[6]
  5. ==>v[1]
  6. ==>v[5]
  7. ==>v[3]
  8. ==>v[1]
  9. gremlin> g.V(1).both().both().simplePath()
  10. ==>v[4]
  11. ==>v[6]
  12. ==>v[5]
  13. ==>v[3]
  14. gremlin> g.V(1).both().both().simplePath().path()
  15. ==>[v[1], v[3], v[4]]
  16. ==>[v[1], v[3], v[6]]
  17. ==>[v[1], v[4], v[5]]
  18. ==>[v[1], v[4], v[3]]

Store

当需要延迟聚合时,可以使用store()替代aggregate(),这里有两点区别:1. 非阻塞。2. 当经过时,存储副作用的对象集合。

  1. gremlin> g.V().aggregate('x').limit(1).cap('x')
  2. ==>{v[1]=1, v[2]=1, v[3]=1, v[4]=1, v[5]=1, v[6]=1}
  3. gremlin> g.V().store('x').limit(1).cap('x')
  4. ==>{v[1]=1, v[2]=1}

Subgraph

subgraph-logo.png-161kB
在对图的分析和开发中,从一个大图中提取一个小图用于分析、可视化或其他目的是很常见的。subgraph()提供了从任意遍历中产生一个边导向的子图(edge-induced subgraph)

  1. gremlin> subGraph = g.E().hasLabel('knows').subgraph('subGraph').cap('subGraph').next() //(1)
  2. ==>tinkergraph[vertices:3 edges:2]
  3. gremlin> sg = subGraph.traversal(standard())
  4. ==>graphtraversalsource[tinkergraph[vertices:3 edges:2], standard]
  5. gremlin> sg.E() //(2)
  6. ==>e[7][1-knows->2]
  7. ==>e[8][1-knows->4]

A more common subgraphing use case is to get all of the graph structure surrounding a single vertex:

  1. gremlin> subGraph = g.V(3).repeat(__.inE().subgraph('subGraph').outV()).times(3).cap('subGraph').next() //(1)
  2. ==>tinkergraph[vertices:4 edges:4]
  3. gremlin> sg = subGraph.traversal(standard())
  4. ==>graphtraversalsource[tinkergraph[vertices:4 edges:4], standard]
  5. gremlin> sg.E()
  6. ==>e[8][1-knows->4]
  7. ==>e[9][1-created->3]
  8. ==>e[11][4-created->3]
  9. ==>e[12][6-created->3]

There can be multiple subgraph() calls within the same traversal. Each operating against either the same graph (i.e. same side-effect key) or different graphs (i.e. different side-effect keys).

  1. gremlin> t = g.V().outE('knows').subgraph('knowsG').inV().outE('created').subgraph('createdG').
  2. inV().inE('created').subgraph('createdG').iterate()
  3. gremlin> t.sideEffects.get('knowsG').get().traversal(standard()).E()
  4. ==>e[7][1-knows->2]
  5. ==>e[8][1-knows->4]
  6. gremlin> t.sideEffects.get('createdG').get().traversal(standard()).E()
  7. ==>e[9][1-created->3]
  8. ==>e[10][4-created->5]
  9. ==>e[11][4-created->3]
  10. ==>e[12][6-created->3]

Sum

求和

  1. gremlin> g.V().values('age').sum()
  2. ==>123
  3. gremlin> g.V().repeat(both()).times(3).values('age').sum()
  4. ==>1471

Tail

tail()limit()类似,获取结果集中的最后的n个。

  1. gremlin> g.V().values('name').order()
  2. ==>josh
  3. ==>lop
  4. ==>marko
  5. ==>peter
  6. ==>ripple
  7. ==>vadas
  8. gremlin> g.V().values('name').order().tail() //(1)
  9. ==>vadas
  10. gremlin> g.V().values('name').order().tail(1) //(2)
  11. ==>vadas
  12. gremlin> g.V().values('name').order().tail(3) //(3)
  13. ==>peter
  14. ==>ripple
  15. ==>vadas

tail()可以与Scope.local配合使用。

  1. gremlin> g.V().as('a').out().as('a').out().as('a').select('a').by(tail(local)).values('name') //(1)
  2. ==>ripple
  3. ==>lop
  4. gremlin> g.V().as('a').out().as('a').out().as('a').select('a').by(unfold().values('name').fold()).tail(local) //(2)
  5. ==>ripple
  6. ==>lop
  7. gremlin> g.V().as('a').out().as('a').out().as('a').select('a').by(unfold().values('name').fold()).tail(local, 2) //(3)
  8. ==>[josh, ripple]
  9. ==>[josh, lop]
  10. gremlin> g.V().valueMap().tail(local) //(4)
  11. ==>[age:[29]]
  12. ==>[age:[27]]
  13. ==>[lang:[java]]
  14. ==>[age:[32]]
  15. ==>[lang:[java]]
  16. ==>[age:[35]]

TimeLimit

Tree

对于任何一个元素,从这里经过的路径都可以被聚合形成tree,gremlin提供了这个功能:tree()
tree-step.png-82.8kB

  1. gremlin> tree = g.V().out().out().tree().next()
  2. ==>v[1]={v[4]={v[3]={}, v[5]={}}}

看看这个过程是怎样的:
tree-step2.png-143kB
这个聚合的树形结构可以被用于其他操作:

  1. gremlin> tree = g.V().out().out().tree().by('name').next()
  2. ==>marko={josh={ripple={}, lop={}}}
  3. gremlin> tree['marko']
  4. ==>josh={ripple={}, lop={}}
  5. gremlin> tree['marko']['josh']
  6. ==>ripple={}
  7. ==>lop={}
  8. gremlin> tree.getObjectsAtDepth(3)
  9. ==>ripple
  10. ==>lop

Unfold

unfold()fold()的反向操作:

  1. gremlin> g.V(1).out().fold().inject('gremlin',[1.23,2.34])
  2. ==>gremlin
  3. ==>[1.23, 2.34]
  4. ==>[v[3], v[2], v[4]]
  5. gremlin> g.V(1).out().fold().inject('gremlin',[1.23,2.34]).unfold()
  6. ==>gremlin
  7. ==>1.23
  8. ==>2.34
  9. ==>v[3]
  10. ==>v[2]
  11. ==>v[4]

Union

ValueMap

获得元素属性,以Map的形式展现。

  1. gremlin> g.V().valueMap()
  2. ==>[name:[marko], age:[29]]
  3. ==>[name:[vadas], age:[27]]
  4. ==>[name:[lop], lang:[java]]
  5. ==>[name:[josh], age:[32]]
  6. ==>[name:[ripple], lang:[java]]
  7. ==>[name:[peter], age:[35]]
  8. gremlin> g.V().valueMap('age')
  9. ==>[age:[29]]
  10. ==>[age:[27]]
  11. ==>[:]
  12. ==>[age:[32]]
  13. ==>[:]
  14. ==>[age:[35]]
  15. gremlin> g.V().valueMap('age','blah')
  16. ==>[age:[29]]
  17. ==>[age:[27]]
  18. ==>[:]
  19. ==>[age:[32]]
  20. ==>[:]
  21. ==>[age:[35]]
  22. gremlin> g.E().valueMap()
  23. ==>[weight:0.5]
  24. ==>[weight:1.0]
  25. ==>[weight:0.4]
  26. ==>[weight:1.0]
  27. ==>[weight:0.4]
  28. ==>[weight:0.2]

非常要注意的是vertex的Map为每个key维护一个list。边或点属性的map代表一个属性(不是一个list)。原因是tinkerpop3中的顶点采用了顶点属性,顶点属性支持一个key可以有多个值。

  1. gremlin> g.V().valueMap()
  2. ==>[name:[marko], location:[san diego, santa cruz, brussels, santa fe]]
  3. ==>[name:[stephen], location:[centreville, dulles, purcellville]]
  4. ==>[name:[matthias], location:[bremen, baltimore, oakland, seattle]]
  5. ==>[name:[daniel], location:[spremberg, kaiserslautern, aachen]]
  6. ==>[name:[gremlin]]
  7. ==>[name:[tinkergraph]]
  8. gremlin> g.V().has('name','marko').properties('location')
  9. ==>vp[location->san diego]
  10. ==>vp[location->santa cruz]
  11. ==>vp[location->brussels]
  12. ==>vp[location->santa fe]
  13. gremlin> g.V().has('name','marko').properties('location').valueMap()
  14. ==>[startTime:1997, endTime:2001]
  15. ==>[startTime:2001, endTime:2004]
  16. ==>[startTime:2004, endTime:2005]
  17. ==>[startTime:2005]

如果需要元素的id,label,key,则在valueMap(boolean need)传一个true属性。

  1. gremlin> g.V().hasLabel('person').valueMap(true)
  2. ==>[label:person, name:[marko], location:[san diego, santa cruz, brussels, santa fe], id:1]
  3. ==>[label:person, name:[stephen], location:[centreville, dulles, purcellville], id:7]
  4. ==>[label:person, name:[matthias], location:[bremen, baltimore, oakland, seattle], id:8]
  5. ==>[label:person, name:[daniel], location:[spremberg, kaiserslautern, aachen], id:9]
  6. gremlin> g.V().hasLabel('person').valueMap(true,'name')
  7. ==>[label:person, name:[marko], id:1]
  8. ==>[label:person, name:[stephen], id:7]
  9. ==>[label:person, name:[matthias], id:8]
  10. ==>[label:person, name:[daniel], id:9]
  11. gremlin> g.V().hasLabel('person').properties('location').valueMap(true)
  12. ==>[startTime:1997, endTime:2001, id:6, key:location, value:san diego]
  13. ==>[startTime:2001, endTime:2004, id:7, key:location, value:santa cruz]
  14. ==>[startTime:2004, endTime:2005, id:8, key:location, value:brussels]
  15. ==>[startTime:2005, id:9, key:location, value:santa fe]
  16. ==>[startTime:1990, endTime:2000, id:10, key:location, value:centreville]
  17. ==>[startTime:2000, endTime:2006, id:11, key:location, value:dulles]
  18. ==>[startTime:2006, id:12, key:location, value:purcellville]
  19. ==>[startTime:2004, endTime:2007, id:13, key:location, value:bremen]
  20. ==>[startTime:2007, endTime:2011, id:14, key:location, value:baltimore]
  21. ==>[startTime:2011, endTime:2014, id:15, key:location, value:oakland]
  22. ==>[startTime:2014, id:16, key:location, value:seattle]
  23. ==>[startTime:1982, endTime:2005, id:17, key:location, value:spremberg]
  24. ==>[startTime:2005, endTime:2009, id:18, key:location, value:kaiserslautern]
  25. ==>[startTime:2009, id:19, key:location, value:aachen]

Vertex Steps

vertex-steps.png-77.1kB
这里包含一下步骤:
1. out(string...): Move to the outgoing adjacent vertices given the edge labels.
2. out(string...): Move to the outgoing adjacent vertices given the edge labels.
3. in(string...): Move to the incoming adjacent vertices given the edge labels.
4. both(string...): Move to both the incoming and outgoing adjacent vertices given the edge labels.
5. outE(string...): Move to the outgoing incident edges given the edge labels.
6. inE(string...): Move to the incoming incident edges given the edge labels.
7. bothE(string...): Move to both the incoming and outgoing incident edges given the edge labels.
8. outV(): Move to the outgoing vertex.
9. inV(): Move to the incoming vertex.
10. bothV(): Move to both vertices.
11. otherV() : Move to the vertex that was not the vertex that was moved from.

举几个例子:

  1. gremlin> g.V(4)
  2. ==>v[4]
  3. gremlin> g.V(4).outE() //(1)
  4. ==>e[10][4-created->5]
  5. ==>e[11][4-created->3]
  6. gremlin> g.V(4).inE('knows') //(2)
  7. ==>e[8][1-knows->4]
  8. gremlin> g.V(4).inE('created') //(3)
  9. gremlin> g.V(4).bothE('knows','created','blah')
  10. ==>e[10][4-created->5]
  11. ==>e[11][4-created->3]
  12. ==>e[8][1-knows->4]
  13. gremlin> g.V(4).bothE('knows','created','blah').otherV()
  14. ==>v[5]
  15. ==>v[3]
  16. ==>v[1]
  17. gremlin> g.V(4).both('knows','created','blah')
  18. ==>v[5]
  19. ==>v[3]
  20. ==>v[1]
  21. gremlin> g.V(4).outE().inV() //(4)
  22. ==>v[5]
  23. ==>v[3]
  24. gremlin> g.V(4).out() //(5)
  25. ==>v[5]
  26. ==>v[3]
  27. gremlin> g.V(4).inE().outV()
  28. ==>v[1]
  29. gremlin> g.V(4).inE().bothV()
  30. ==>v[1]
  31. ==>v[4]

Where

where()经常配合match()select()使用,但也可以单独使用。

  1. gremlin> g.V(1).as('a').out('created').in('created').where(neq('a')) //(1)
  2. ==>v[4]
  3. ==>v[6]
  4. gremlin> g.withSideEffect('a',['josh','peter']).V(1).out('created').in('created').values('name').where(within('a')) //(2)
  5. ==>josh
  6. ==>peter
  7. gremlin> g.V(1).out('created').in('created').where(out('created').count().is(gt(1))).values('name') //(3)
  8. ==>josh

where()可以过滤任意的遍历结果的任意对象:

  1. gremlin> g.V().where(out('created')).values('name') //(1)
  2. ==>marko
  3. ==>josh
  4. ==>peter
  5. gremlin> g.V().out('knows').where(out('created')).values('name') //(2)
  6. ==>josh
  7. gremlin> g.V().where(out('created').count().is(gte(2))).values('name') //(3)
  8. ==>josh
  9. gremlin> g.V().where(out('knows').where(out('created'))).values('name') //(4)
  10. ==>marko
  11. gremlin> g.V().where(__.not(out('created'))).where(__.in('knows')).values('name') //(5)
  12. ==>vadas
  13. gremlin> g.V().where(__.not(out('created')).and().in('knows')).values('name') //(6)
  14. ==>vadas

判断语句

语句 说明
eq(object) 是否相等
neq(object) 是否不相等
lt(number) 小于
lte(number) 小于等于
gt(number) 大于
gte(number) 大于等于
inside(number1,number2) >number1 && <number2
outside(number1,number2) >number2 | <number1
between(number1,number2) <=number1 | >=number2
within(objects...) 是否包含
without(objects...) 是否不包含
  1. gremlin> eq(2)
  2. ==>eq(2)
  3. gremlin> not(neq(2)) //(1)
  4. ==>eq(2)
  5. gremlin> not(within('a','b','c'))
  6. ==>without([a, b, c])
  7. gremlin> not(within('a','b','c')).test('d') //(2)
  8. ==>true
  9. gremlin> not(within('a','b','c')).test('a')
  10. ==>false
  11. gremlin> within(1,2,3).and(not(eq(2))).test(3) //(3)
  12. ==>true
  13. gremlin> inside(1,4).or(eq(5)).test(3) //(4)
  14. ==>true
  15. gremlin> inside(1,4).or(eq(5)).test(5)
  16. ==>true
  17. gremlin> between(1,2) //(5)
  18. ==>and([gte(1), lt(2)])
  19. gremlin> not(between(1,2))
  20. ==>or([lt(1), gte(2)])

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注