gremlin3.3.3 第三部分 - 1-图的遍历(1)

图的遍历

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5o1ByO4e-1596172178971)(media/53fa873a622323b2fb4ddcb0be1c4a35.png)]

在最一般的层次上,有Traversal<S,E> ,它实现了Iterator<E> ,其中S代表开始,E代表结束。遍历由四个主要组件组成:

  1. Step<S,E> :应用于S产生E的单个函数。

  2. TraversalStrategy:拦截器方法来改变遍历的执行(例如,查询、重写)。

  3. TraversalSideEffects:可用于存储关于遍历的全局信息的键/值对。

  4. Traverser<T> :在遍历中传播的对象,当前表示类型为T的对象。

GraphTraversal<S,E> 提供了图遍历的经典概念,它扩展自Traversal<S,E> 。GraphTraversal 提供了graph 数据的顶点、边等方面的翻译,从而实现了图形遍历DSL。

IMPORTANTTinkerPop提供的底层Step实现包含DSL作者需要的大部分功能。DSL作者利用提供的Step是很重要的,因为这样通用优化和装饰策略就可以根据底层遍历序列推理。如果引入了新的Step,则公用的遍历策略可能无法正常运行。

图遍历的步骤

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aKtF4ixa-1596172178973)(media/2c5344b60f36a2396e0f139d71a45715.png)]

GraphTraversal<S,E>是从GraphTraversalSource派生的。它也可以通过__.
匿名产生(即empty)。GraphTraversal 由一系列有序的step组成。GraphTraversal 提供的所有步骤都继承了上面所示的普通形式。TinkerPop3
GraphTraversal JavaDoc中提供了所有step
(及其描述)的列表。下面的小节将演示在Gremlin控制台使用GraphTraversal step的流程。

IMPORTANTGraph Process章节及章节描述了使用遍历的基础知识。
NOTE为了避免表达式的冗长写法,最好是使用 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph..*。这样,在遍历中可以用inE()代替.inE()的写法。在使用匿名遍历时,注意语言的保留关键字。例如,in和as在Groovy中是保留关键字,因此必须使用详细语法 .in()和.as ()避免冲突。

General (常用)Step

有五个常规Step,均支持遍历和lambda,后面描述的所有Step都是通过这些步骤进行扩展使用。

Step描述
map(Traversal<S, E>) map(Function<Traverser<S>, E>)遍历映射S为对象E,供下一个Step处理。
flatMap(Traversal<S, E>) flatMap(Function<Traverser<S>, Iterator<E>>)遍历映射S为对象E并流化处理。
filter(Traversal<?, ?>) filter(Predicate<Traverser<S>>)返回ture或false,false的记录不会传递到下一个Step。
sideEffect(Traversal<S, S>) sideEffect(Consumer<Traverser<S>>)执行一些操作,并将其传递到下一Step。
branch(Traversal<S, M>) branch(Function<Traverser<S>,M>)以M标记的索引分割遍历。
WARNINGLambda步骤是为了教学目的而提供的,因为它们表示Gremlin语言的基本构成。在实践中,应该避免lambda步骤,以支持它们的遍历显示,除非显式地“关闭”,遍历验证策略中不允许使用。有关lambdas的更多信息,请阅读。

Traverser<S>有以下访问形式:

  1. 获取当前Traverser对象S—Traverser.get()。

  2. 当前Traverser对象的路径—traverser .path()。

    1. 获取指定历史路径记录的对象—Traverser.path(String) ==
      Traverser.path().get(String)。
  3. 当前对象的遍历次数—traverser .loops()。

  4. 当前遍历器所代表的对象数目—traverser .bulk()。

  5. 当前遍历器关联的本地数据结构—traverser .sack()。

  6. 当前遍历器的附加作用—traver . sideeffects()。

    1. 获取指定附加作用—Traverser.sideEffect(String) ==
      Traverser.sideEffects().get(String)。
      在这里插入图片描述
>   gremlin\> g.V(1).out().values('name')

>   [./media/image3.png](./media/image3.png)

>   map lambda

>   ==\>lop

>   ==\>vadas

>   ==\>josh

>   gremlin\> g.V(1).out().map {it.get().value('name')}

>   ==\>lop

>   ==\>vadas

>   ==\>josh

>   gremlin\> g.V(1).out().map(values('name'))

>   ==\>lop

>   ==\>vadas

>   ==\>josh
  1. 从顶点1向外遍历相邻顶点的name属性值。

  2. 含义同上,换成使用lambda访问name属性值的形式。

  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'))

>   ==\>v[1]

>   ==\>v[2]

>   ==\>v[4]

>   ==\>v[6]

>   gremlin\> g.V().hasLabel('person')

>   ==\>v[1]

>   ==\>v[2]

>   ==\>v[4]

>   ==\>v[6]
  1. 在全部顶点中查找label=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().store("o")).

>   sideEffect(inE().count().store("i")).cap("o","i")

>   ==\>[i:[0,0,1,1,1,3],o:[3,0,0,0,2,1]]
  1. 进入sideEffect()的内容将被传递到下一Step,并被打印。

  2. 计算每个顶点的进出度,以o和i分别代表结果。两个sideEffect
    ()都针对同一个的顶点。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ic41TKZn-1596172178974)(media/b62c7319f2299a55fcb68e641055f8f6.png)]

>   gremlin\> g.V().branch {it.get().value('name')}.

>   option('marko', values('age')).

>   option(none, values('name'))

>   ==\>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'))

>   ==\>29

>   ==\>vadas

>   ==\>lop

>   ==\>josh

>   ==\>ripple

>   ==\>peter
  1. 使用branch,用it遍历顶点,如果顶点是“marko”,获取age,否则得到顶点的name。

  2. 含义同上,使用branch()的遍历形式。

  3. 含义同上,使用choose()代替branch()功能,choose返回true false 表达式为
    choose(condition-step,true-result-step,false-result-step)。

Terminal(终端) Step

通常,当一个Step串联到一个traversal 时,将返回一个traversal 。这样,一个遍历就以流畅的、一元的方式建立起来。但是,有些Step不返回traversal ,而是执行traversal 并返回结果。这些Step称为终端步骤(terminal),样例如下。

>   gremlin\> g.V().out('created').hasNext()

>   ==\>true

>   gremlin\> g.V().out('created').next()

>   ==\>v[3]

>   gremlin\> g.V().out('created').next(2)

>   ==\>v[3]

>   ==\>v[5]

>   gremlin\> g.V().out('nothing').tryNext()

>   ==\>Optional.empty

>   gremlin\> g.V().out('created').toList()

>   ==\>v[3]

>   ==\>v[5]

>   ==\>v[3]

>   ==\>v[3]

>   gremlin\> g.V().out('created').toSet()

>   ==\>v[3]

>   ==\>v[5]

>   gremlin\> g.V().out('created').toBulkSet()

>   ==\>v[3]

>   ==\>v[3]

>   ==\>v[3]

>   ==\>v[5]

>   gremlin\> results = ['blah',3]

>   ==\>blah

>   ==\>3

>   gremlin\> g.V().out('created').fill(results)

>   ==\>blah

>   ==\>3

>   ==\>v[3]

>   ==\>v[5]

>   ==\>v[3]

>   ==\>v[3]

>   gremlin\> g.addV('person').iterate() *//*
  1. hasNext() 确认是否有可用结果 返回true /false。

  2. next() 返回下一个结果。

  3. next(n) 将返回next列表中的第n个结果。

  4. tryNext() 返回一个Optional 对象,可看做hasNext()/next()的组合。

  5. toList() 以List形式返回结果。

  6. toSet() 以Set形式返回结果(起到去重的作用)。

  7. toBulkSet() 返回一个加权List(通过加权保留可重复项)。

  8. fill(集合) 把结果放到一个已定义的集合中,返回该集合。

  9. iterate()并不完全符合终端步骤的定义,因为它不返回结果,但仍然返回遍历——但它的行为确实像终端步骤,因为它迭代遍历并产生了附加作用,附加作用的结果就是不返回实际结果。

最后,explain()-step也是一个结束步骤,在随后的章节中进行描述。

AddEdge(增加边) Step

推断是指使数据中隐含的内容显式的过程。在graph 中显式的是graph 的对象。例如对graph 进行遍历时指的就是顶点和边。换句话说,traversal显示的内容含义由traversal的定义决定。例如,以“co-developers”的概念为例。如果两个人一起做过同一个项目,那么他们就是co-developers。这个概念适用于traversal,因此。此外,隐式操作可以通过addE()-step
(map/sideEffect)来显式调用。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZHE4wnb2-1596172178976)(media/b49c56acc83e5002413e85a1d916ad93.png)]

>   gremlin\> g.V(1).as('a').out('created').in('created').where(neq('a')).
>   addE('co-developer').from('a').property('year',2009)

>   ==\>e[13][1-co-developer-\>4]

>   ==\>e[14][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')

>   ==\>e[15][3-createdBy-\>4]

>   ==\>e[16][5-createdBy-\>4]

>   gremlin\>
>   g.V().as('a').out('created').addE('createdBy').to('a').property('acl','public')
>   \\

>   ==\>e[17][3-createdBy-\>1]

>   ==\>e[18][5-createdBy-\>4]

>   ==\>e[19][3-createdBy-\>4]

>   ==\>e[20][3-createdBy-\>6]

>   gremlin\> g.V(1).as('a').out('knows').
>   addE('livesNear').from('a').property('year',2009).

>   inV().inE('livesNear').values('year') \\

>   ==\>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'))

>   ==\>e[23][1-friendlyCollaborator-\>4]

>   gremlin\> g.E(23).valueMap()

>   ==\>[project:lop]

>   gremlin\> marko = g.V().has('name','marko').next()

>   ==\>v[1]

>   gremlin\> peter = g.V().has('name','peter').next()

>   ==\>v[6]

>   gremlin\> g.V(marko).addE('knows').to(peter)

>   ==\>e[24][1-knows-\>6]

>   gremlin\> g.addE('knows').from(marko).to(peter)

>   ==\>e[25][1-knows-\>6]
  1. 在marko(也就是示例图中V(1)的顶点)和与他合作者(out)的合作商(in)之间创建一条“ co-developer”的Edge,并设置属性year=2009(虚线部分)。

  2. 以3、4、5的顶点作为集合x,从x中找到name=josh的顶点结果作为a,从x中找到有label=software的顶点,添加“createdBy”
    边到a中,最终的结论就是添加从josh顶点到lop顶点传入边“createdBy”。

  3. 为具有出边“created”的顶点创建“createdBy”并且属性
    acl=public的入边,最终效果是为带“created”出边的顶点都添加一个“createdBy”入边。

  4. 对新创建的edge 也可进行遍历

  5. traversal 中的两个任意绑定可以用from()→`to()来连接, `id可以为用户提供id。

  6. 在marko和peter之间添加一条有向(单向)边(label= knows)。

  7. 意义同上,写法不一样。

其他用法

addE(String), addE(Traversal)

AddVertex(增加顶点) Step

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

>   gremlin\> g.addV('person').property('name','stephen')

>   ==\>v[13]

>   gremlin\> g.V().values('name')

>   ==\>marko

>   ==\>vadas

>   ==\>lop

>   ==\>josh

>   ==\>ripple

>   ==\>peter

>   ==\>stephen

>   gremlin\> g.V().outE('knows').addV().property('name','nothing')

>   ==\>v[15]

>   ==\>v[17]

>   gremlin\> g.V().has('name','nothing')

>   ==\>v[17]

>   ==\>v[15]

>   gremlin\> g.V().has('name','nothing').bothE()

其他用法

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

AddProperty(增加属性) Step

property()-step用于向graph
(sideEffect)的元素添加属性与addV()和addE()不同,property()是一个完全的sideEffect 步骤,因为它不返回它创建的属性,而是返回流进其中的元素。此外,如果property()遵循addV()或addE(),那么它将被“折叠”到前面的步骤中,在一次创建操作中启用顶点和边的所有属性。

>   gremlin\> g.V(1).property('country','usa')

>   ==\>v[1]

>   gremlin\> g.V(1).property('city','santa fe').property('state','new
>   mexico').valueMap()

>   ==\>[country:[usa],city:[santa fe],name:[marko],state:[**new**
>   mexico],age:[29]]

>   gremlin\> g.V(1).property(list,'age',35)

>   ==\>v[1]

>   gremlin\> g.V(1).valueMap()

>   ==\>[country:[usa],city:[santa fe],name:[marko],state:[**new**
>   mexico],age:[29,35]]

>   gremlin\>
>   g.V(1).property('friendWeight',outE('knows').values('weight').sum(),'acl','private')

>   ==\>v[1]

>   gremlin\> g.V(1).properties('friendWeight').valueMap() \\

>   ==\>[acl:**private**]
  1. 对于顶点,可以为顶点属性提供基数。

  2. 可以通过遍历选择属性值(以及键)。

  3. 对于顶点,property()-step可以添加元属性。

其他用法

property(Object, Object,
Object…​)
, property(Cardinality,
Object, Object,
Object…​)
, Cardinality

Aggregate(聚合) Step

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v9D2PVUV-1596172178977)(media/1cb2f4419facbf259242c979254da48a.png)]

aggregate()-step
(sideEffect)用于将特定的遍历点上的所有对象聚合到一个集合中。该步骤使用了急求,因为在之前的所有对象都被完全聚合之前,任何对象都不会继续(与延迟填充集合的store()相反)。在需要在特定点上的所有东西用于未来计算的情况下,急于求值的性质非常重要。下面提供了一个示例。

>   gremlin\> g.V(1).out('created') \\

>   ==\>v[3]

>   gremlin\> g.V(1).out('created').aggregate('x') \\

>   ==\>v[3]

>   gremlin\> g.V(1).out('created').aggregate('x').in('created')

>   ==\>v[1]

>   ==\>v[4]

>   ==\>v[6]

>   gremlin\> g.V(1).out('created').aggregate('x').in('created').out('created')

>   ==\>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') 5
>   ==\>ripple
  1. marko创造了什么?

  2. 集合了marko 的所有创作。

  3. 谁是marko的合作者?

  4. marko的合作者创造了什么?

  5. 马可的合作者创造了什么他没有创造的?

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

“user A喜欢什么?”还有谁喜欢这些东西?他们喜欢的哪些东西是user A不喜欢的?”

最后,可以通过by()-对aggregate()-step进行调节。

>   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]

其他用法

aggregate(String)

And(与) Step

and()步骤让traversal产生一个过滤结果。参阅 or()来了解or语义。

>   gremlin\> g.V().and(

>   outE('knows'),

>   values('age').is(lt(30))).

>   values('name')

>   ==\>marko

and()步骤可以执行多次。所有traversal都必须为原始遍历器生成至少一个输出,以便传递给下一Step。

也可以使用中缀表示法。但是,使用中缀表示法只能支持两个遍历。

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

>   ==\>marko

其他用法

and(Traversal…​)

As(别名) Step

as()步骤不是一个真正的步骤,而是一个类似by()和option()的“step调解器”。有了as(),就有可能为step提供一个label,稍后使用这些标签的step和数据结构可以访问这个标签。例如select()、match()和path。

>   gremlin\> g.V().as('a').out('created').as('b').select('a','b')

>   ==\>[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')

>   ==\>[a:marko,b:lop]

>   ==\>[a:josh,b:ripple]

>   ==\>[a:josh,b:lop]

>   ==\>[a:peter,b:lop]
  1. 从path中选择标记为“a”和“b”的对象。

  2. 从path中选择标记为“a”和“b”的对象,并对每个对象获取其name值。

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

>   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]]

其他用法

as(String,String…​)

  1. 从path中选择标记为“a”和“b”的对象。

  2. 从path中选择标记为“a”和“b”的对象,并对每个对象获取其name值。

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

>   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]]

其他用法

as(String,String…​)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值