TinkerPop Gremlin基础概念
- 图计算在结构(图)和过程(遍历)之间进行区分。
- 图的
结构
是由顶点/边/属性拓扑定义的数据模型。 - 图的
过程
是分析结构的手段。图形处理的典型形式称为遍历
。
- 图的
TinkerPop3 结构 API的主要组件:
Graph:维护一组顶点和边,并访问数据库函数(如
事务
)。Element:维护一组属性和一个表示元素类型的字符串
标签
。Vertex:扩展Element并维护一组传入和传出
顶点
。Edge:扩展Element并维护传入和传出
边缘
。Property
<V>
:与V值关联的字符串键。VertexProperty
<V>
:与V值关联的字符串键以及Property<U>
属性集合(仅限顶点)
TinkerPop3 过程 API的主要组件
TraversalSource:针对特定图形,域特定语言(DSL)和执行引擎的遍历生成器。
Traversal
<S,E>
:将类型的S对象转换为类型对象的功能数据流程E。GraphTraversal:面向原始图的语义(即顶点,边等)的遍历DSL。
GraphComputer:一个并行处理图形并且可能分布在多机群集上的系统。
VertexProgram:在所有顶点以逻辑并行方式执行的代码,通过消息传递进行相互通信。
MapReduce:并行分析图中所有顶点并产生单个减少结果的计算。
图形结构
- 图
结构
:
- 图的结构是由其顶点,边和属性之间的显式引用形成的拓扑。
- 顶点具有入射边。如果一个顶点共享一个入射边,则该顶点与另一个顶点相邻。
- 一个属性附加到一个元素上,一个元素具有一组属性。属性是一个键/值对,其中键总是一个字符String。
Graph graph = TinkerGraph.open(); //1.创建一个新的内存TinkerGraph并将其分配给该变量graph。
Vertex marko = graph.addVertex(T.label, "person", T.id, 1, "name", "marko", "age", 29); //2.创建一个顶点以及一组键/值对T.label作为顶点标签并且T.id是顶点ID。
Vertex vadas = graph.addVertex(T.label, "person", T.id, 2, "name", "vadas", "age", 27);
Vertex lop = graph.addVertex(T.label, "software", T.id, 3, "name", "lop", "lang", "java");
Vertex josh = graph.addVertex(T.label, "person", T.id, 4, "name", "josh", "age", 32);
Vertex ripple = graph.addVertex(T.label, "software", T.id, 5, "name", "ripple", "lang", "java");
Vertex peter = graph.addVertex(T.label, "person", T.id, 6, "name", "peter", "age", 35);
marko.addEdge("knows", vadas, T.id, 7, "weight", 0.5f); //3.边缘标签被指定为第一个参数的同时创建边缘以及一组键/值对。
marko.addEdge("knows", josh, T.id, 8, "weight", 1.0f);
marko.addEdge("created", lop, T.id, 9, "weight", 0.4f);
josh.addEdge("created", ripple, T.id, 10, "weight", 1.0f);
josh.addEdge("created", lop, T.id, 11, "weight", 0.4f);
peter.addEdge("created", lop, T.id, 12, "weight", 0.2f);
- 实例分析:
- 首先创建所有顶点
Graph.addVertex(Object…)
,然后创建它们各自的边Vertex.addEdge(String,Vertex,Object…)
。有两个“访问者令牌”: T.id和T.label。 - 相应的元素连同提供的键/值对属性一起被创建
"name", "josh", "age", 32
。
- 首先创建所有顶点
遍历过程
图表
过程
GraphTraversalSource提供了两种遍历方法:
- GraphTraversalSource.V(Object… ids):生成从图中顶点开始的遍历(如果没有提供id,则为所有顶点)。
- GraphTraversalSource.E(Object… ids):生成从图中边缘开始的遍历(如果没有提供id,则为所有边)。
- 返回类型V()和E()是GraphTraversal。
每种方法GraphTraversal称为一个步骤,每个步骤以五种常规方式之一调整前一步骤的结果。
map:将传入的遍历器的对象转换为另一个对象(S→E)。
flatMap:将传入的遍历器的对象转换为其他对象的迭代器(S→E *)。
filter:允许或禁止移动机进行下一步(S→E→S)。
sideEffect:允许移动者不改变,但在过程中产生一些计算副作用(S↬S)。
branch:分割移动器并将每个发送到遍历中的任意位置(S→{S 1 →E ,…,S n →E }→E *)。
- Nearly every step in GraphTraversal either extends MapStep, FlatMapStep, FilterStep, SideEffectStep, or BranchStep.
$ bin/gremlin.sh
\,,,/
(o o)
-----oOOo-(3)-oOOo-----
gremlin> graph = TinkerFactory.createModern() //1.打开玩具图并通过变量引用它graph。
==>tinkergraph[vertices:6 edges:6]
gremlin> g = graph.traversal() //2.使用标准的OLTP遍历引擎从图中创建一个图遍历源。
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> g.V().has('name','marko').out('knows').values('name') //3.从遍历源中产生一个遍历,以确定标记顶点知道的人的名字。
==>vadas
==>josh
gremlin> marko = g.V().has('name','marko').next() //1.将变量设置为名为“marko” marko的图形中的顶点g。
==>v[1]
gremlin> g.V(marko).out('knows') //2.通过知识边获取与标记顶点相邻的传出顶点。
==>v[2]
==>v[4]
gremlin> g.V(marko).out('knows').values('name') //3.获取marko-vertex的朋友的名字。
==>vadas
==>josh
- 遍历器的路径历史记录
gremlin> g.V(marko).out('knows').values('name').path()
==>[v[1],v[2],vadas]
==>[v[1],v[4],josh]
- 遍历器遍历遍历表达式的特定部分(即循环)的次数
gremlin> g.V(marko).repeat(out()).times(2).values('name')
==>ripple
==>lop
顶点属性
- a的所有属性Vertex都是a VertexProperty。A VertexProperty实现Property,因此它有一个键/值对。
- 但是,VertexProperty也可以实现Element并因此可以具有键/值对的集合
- 虽然Edge只能有一个“name”键的属性,但是Vertex可以有多个“name”属性。通过包含顶点属性,引入了两个功能,最终推进了图形建模工具包:
- 多个属性(多属性):顶点属性键可以有多个值。例如,一个顶点可以有多个“name”属性。
- Properties on properties(元属性):顶点属性可以具有属性(即,顶点属性可以具有与其关联的键/值数据)
图事务
- 一个数据库事务 代表的工作单位来对数据库执行。
- 事务由Transaction接口的实现控制, 并且该对象可以Graph使用该tx()方法从接口获取。
- 请注意,该Transaction对象本身并不代表“事务”。它只是公开了处理事务的方法(例如提交,回滚等)。
- 大部分Graph是实现supportsTransactions将实现“自动” ThreadLocal交易,这意味着当后一个读或写操作时Graph被实例化,事务就会自动线程内开始。
- 没有必要手动调用一个方法来“创建”或“启动”一个事务。只需根据需要修改图形,然后致电graph.tx().commit()以应用更改或graph.tx().rollback()撤消它们。当下一个读取或写入操作发生在图上时,将在当前执行线程中启动一个新的事务。
遍历
遍历由四个主要组成部分组成:
Step
<S,E>
:应用于S产出的单个函数E。步骤在遍历内链接。TraversalStrategy:拦截器方法来改变遍历的执行(例如查询重写)。
TraversalSideEffects:可用于存储有关遍历的全局信息的键/值对。
Traverser
<T>
:通过Traversal当前表示类型的对象传播的对象T。
- 图形遍历的经典概念GraphTraversal
<S,E>
由此扩展而来Traversal<S,E>
。 GraphTraversal根据顶点,边缘等提供对图数据的解释,并因此提供图遍历DSL。
该Traverser
<S>
对象可以访问:当前遍历的S对象 - Traverser.get()。
遍历器遍历的当前路径 - Traverser.path()。
获取特定路径历史对象的助手速记 - Traverser.path(String) == Traverser.path().get(String)。
遍历器通过当前循环的次数 - Traverser.loops()。
这个遍历器表示的对象的数量 - Traverser.bulk()。
与此遍历器相关的本地数据结构 - Traverser.sack()。
与遍历相关的副作用 - Traverser.sideEffects()。
gremlin> g.V(1).out().values('name') //1.从顶点1到相邻顶点的名称值的传出遍历。
==>lop
==>vadas
==>josh
gremlin> g.V(1).out().map {it.get().value('name')} //2.相同的操作,但使用lambda来访问名称属性值。
==>lop
==>vadas
==>josh
gremlin> g.V(1).out().map(values('name')) //3.同样的操作,但使用遍历表示map()。
==>lop
==>vadas
==>josh
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.更具体的步骤has()是filter()用各自的谓词来实现的。
==>v[1]
==>v[2]
==>v[4]
==>v[6]
gremlin> g.V().branch {it.get().value('name')}.
option('marko', values('age')).
option(none, values('name')) //1.如果顶点是“marko”,则获取他的年龄,否则获取顶点的名称。
==>29
==>vadas
==>lop
==>josh
==>ripple
==>peter
gremlin> g.V().branch(values('name')).
option('marko', values('age')).
option(none, values('name')) //2.相同的操作,但使用遍历表示branch()。
==>29
==>vadas
==>lop
==>josh
==>ripple
==>peter
gremlin> g.V().choose(has('name','marko'),
values('age'),
values('name')) //3.更具体的基于布尔的步骤choose()被实现为a branch()。
==>29
==>vadas
==>lop
==>josh
==>ripple
==>peter
Terminal
- 通常,当一个步骤连接到一个遍历时,返回一个遍历。通过这种方式,流畅的,单点式的遍历就可以建立起来。
- 但是,某些步骤不会返回遍历,而是执行遍历并返回结果。这些步骤被称为终端步骤(终端)
gremlin> g.V().out('created').hasNext() //1.hasNext() 确定是否有可用的结果。
==>true
gremlin> g.V().out('created').next() //2.next() 将返回下一个结果。
==>v[3]
gremlin> g.V().out('created').next(2) //3.next(n)将返回n列表中的下一个结果。
==>v[3]
==>v[5]
gremlin> g.V().out('nothing').tryNext() //4.tryNext()将返回一个Optional,因此,是hasNext()/ 的组合next()。
==>Optional.empty
gremlin> g.V().out('created').toList() //5.tryNext()将返回一个Optional,因此,是hasNext()/ 的组合next()。
==>v[3]
==>v[5]
==>v[3]
==>v[3]
gremlin> g.V().out('created').toSet() //6.toSet() 将返回一个集合中的所有结果(因此,重复删除)。
==>v[3]
==>v[5]
gremlin> g.V().out('created').toBulkSet() //7.toBulkSet() 将返回加权集合中的所有结果(因此,通过加权保留重复)。
==>v[3]
==>v[3]
==>v[3]
==>v[5]
gremlin> results = ['blah',3]
==>blah
==>3
gremlin> g.V().out('created').fill(results) //8.fill(collection) 会将所有结果放入提供的集合中,并在完成时返回集合。
==>blah
==>3
==>v[3]
==>v[5]
==>v[3]
==>v[3]
gremlin> g.addV('person').iterate() // 9.iterate() 并不完全符合终端步骤的定义,因为它不返回结果,但仍然返回一个遍历 - 但它确实表现为终端步骤,它重复遍历并生成副作用而不返回实际结果。
AddEdge
推理
是明确数据中隐含的内容的过程.- 图中
显式
的是图的对象 - 即顶点
和边
。 - 图中
隐含
的是遍历
。
- 换句话说,遍历揭示了意义由遍历定义确定的位置。
gremlin> g.V(1).as('a').out('created').in('created').where(neq('a')).
addE('co-developer').from('a').property('year',2009) //1.在marko和他的合作者之间添加一个年度财产的合作开发者边缘。
==>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') //2.将来自josh顶点的传入createdBy边添加到lop和波纹顶点。
==>e[15][3-createdBy->4]
==>e[16][5-createdBy->4]
gremlin> g.V().as('a').out('created').addE('createdBy').to('a').property('acl','public') //3.为所有创建的边添加一个反向创建的边。
==>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') //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.可以加入遍历中的任意两个绑定from()→ , where `id可以为支持用户提供的id的图提供`to()。
==>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) //6.给定定向(分离)的顶点参考,在marko和peter之间添加一条边。
==>e[24][1-knows->6]
gremlin> g.addE('knows').from(marko).to(peter) //7.给定定向(分离)的顶点参考,在marko和peter之间添加一条边。
==>e[25][1-knows->6]
AddVertex
- 所述addV()-step用于顶点添加到图表(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()
AddProperty
- The property():步骤用于将属性添加到的曲线图的元素sideEffect。
- 不像addV()和 addE(),property()是一个完整的sideEffect一步,因为它不会返回它创造的财产,而是涌入它的元素。
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) //1.对于顶点,可以为顶点属性提供基数。
==>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') //2.可以通过遍历来选择属性值(以及键)。
==>v[1]
gremlin> g.V(1).properties('friendWeight').valueMap() //3.对于顶点,property()-step可以添加元属性。
==>[acl:private]
Aggregate
- aggregate()工序(sideEffect)用于在特定点遍历成聚集的所有对象 Collection。
- The step uses eager evaluation in that no objects continue on until all previous objects have been fully aggregated (as opposed to store() which lazily fills a collection). The eager evaluation nature is crucial in situations where everything at a particular point is required for future computation. An example is provided below.
gremlin> g.V(1).out('created') //1。marko创建了什么?
==>v[3]
gremlin> g.V(1).out('created').aggregate('x') //2。汇总他所有的创作。
==>v[3]
gremlin> g.V(1).out('created').aggregate('x').in('created') //3。谁是marko的合作者?
==>v[1]
==>v[4]
==>v[6]
gremlin> g.V(1).out('created').aggregate('x').in('created').out('created') //4。marko的合作者创造了什么?
==>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。Marko的合作者创建了什么,他没有创建?
==>ripple
And
- The and():确保所有提供遍历得到的结果(滤波)
gremlin> g.V().and(
outE('knows'),
values('age').is(lt(30))).
values('name')
==>marko
- 一个中间符号可以被使用。尽管用中缀符号表示,但只有两次遍历可以在一起。
gremlin> g.V().where(outE('created').and().outE('knows')).values('name')
==>marko
As
- The as():不是一个真正的步骤,而是一个类似于by()和的“步调制器” option()。
- 用as(),有可能提供一个标签到可稍后通过步骤和数据结构,使这些标记的使用被访问的步骤-例如select(),match()和路径。
gremlin> g.V().as('a').out('created').as('b').select('a','b') //1.从路径中选择标记为“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') //2.从路径中选择标记为“a”和“b”的对象,并为每个对象设置其名称值。
==>[a:marko,b:lop]
==>[a:josh,b:ripple]
==>[a:josh,b:lop]
==>[a:peter,b:lop]
- 一个步骤可以有任何数量的标签与之相关联。这对于在未来的步骤中多次引用同一步骤很有用。
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]]
Barrier
- The barrier():(屏障)变为懒惰遍历流水线成批量同步管道。
- 此步骤很有用:
- 当所有的事情都需要被执行之后才能进入barrier()(即排序)之后的步骤。
- 当“stalling”遍历可能导致遍历中的“bulking optimization”,这种遍历反复触及许多相同的元素(即优化)。
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]
- “bulking optimization”背后的理论很简单。
- 如果在顶点1处有一百万个遍历器,则不需要计算一百万个both()计算。相反,将这100万遍历作为一个Traverser.bulk()等于一百万的遍历器来表示,并执行both()一次。
gremlin> graph = TinkerGraph.open()
==>tinkergraph[vertices:0 edges:0]
gremlin> graph.io(graphml()).readGraph('data/grateful-dead.xml')
gremlin> g = graph.traversal().withoutStrategies(LazyBarrierStrategy) //1.明确地删除LazyBarrierStrategy这会产生一个膨胀优化。
==>graphtraversalsource[tinkergraph[vertices:808 edges:8049], standard]
gremlin> clockWithResult(1){g.V().both().both().both().count().next()} //2.处理每个移动程序的非扩充遍历。
==>10555.215011999999
==>126653966
gremlin> clockWithResult(1){g.V().repeat(both()).times(3).count().next()} //3.每个进入者repeat()都有其递归权重。
==>32.586223
==>126653966
gremlin> clockWithResult(1){g.V().both().barrier().both().barrier().both().barrier().count().next()} //4.没有处理隐式遍历的遍历遍历。
==>24.458371
==>126653966
- 如果barrier()提供了一个整数参数,那么在将n聚合遍历器排空到下一步之前,屏障将只保留唯一遍历器的数量。
- LazyBarrierStrategy插入 - barrier()在适当的地方进行遍历,以获得“膨胀优化”。
gremlin> graph = TinkerGraph.open()
==>tinkergraph[vertices:0 edges:0]
gremlin> graph.io(graphml()).readGraph('data/grateful-dead.xml')
gremlin> g = graph.traversal() //1.LazyBarrierStrategy 是一种默认策略,因此不需要明确激活。
==>graphtraversalsource[tinkergraph[vertices:808 edges:8049], standard]
gremlin> clockWithResult(1){g.V().both().both().both().count().next()}
==>15.593098999999999
==>126653966
gremlin> g.V().both().both().both().count().iterate().toString() //2.与LazyBarrierStrategy激活,barrier()步骤被自动插入在适当情况下。
==>[TinkerGraphStep(vertex,[]), VertexStep(BOTH,vertex), NoOpBarrierStep(2500), VertexStep(BOTH,vertex), NoOpBarrierStep(2500), VertexStep(BOTH,edge), CountGlobalStep, NoneStep]
By
- The by():一步不是一个实际的步骤,而是一个类似于as()和 的“阶跃调节器” 。
- 如果一个步骤能够接受遍历,函数,比较等,那么by()就是它们被添加的方式。一般模式是step().by()…by()。有些步骤只能接受一个,by() 而其他步骤可以采取任意数量。
gremlin> g.V().group().by(outE().count()) //1.by(outE().count())将按元素的边数(遍历)对元素进行分组。
==>[1:[v[2],v[5],v[6]],3:[v[1],v[3],v[4]]]
gremlin> g.V().group().by(bothE().count()).by('name') //2.by('name')将按名称处理分组元素(元素属性投影)。
==>[1:[vadas,ripple,peter],3:[marko,lop,josh]]
gremlin> g.V().group().by(bothE().count()).by(count()) //3.by(count())将计算每个组中元素的数量(遍历)。
==>[1:3,3:3]
以下步骤都支持by()调制:
dedup():对调制结果进行by()重复数据删除。
cyclicPath():如果遍历器的路径是循环给定by()调制,则进行过滤。
simplePath():如果遍历器的路径在给定by()调制的情况下是简单的,则进行过滤。
sample():使用由by()调制返回的值进行采样。
where():确定给定测试结果的谓词 - by()调制。
groupCount():计数那些组密钥是by()调制结果的组。
group():根据by()-modulation 创建组键和值。
order():通过by()调制的结果对对象进行排序。
path():获取每个路径元素被by()调制的遍历器的路径。
project():by()从当前对象中投影给定各种调制结果的地图。
select():选择路径元素并通过by()调制进行转换。
tree():获取对象已被by()调制的遍历器对象树。
aggregate():将所有对象聚合到一个集合中,但只存储它们的by()-modulated值。
store():将所有对象存储到一个集合中,但只存储它们的by()-modulated值。
Cap
- The cap(): 迭代遍历到本身并发射通过所提供的密钥所引用的sideEffect。如果提供了多个键,则会Map
gremlin> g.V().groupCount('a').by(label).cap('a') //1.按标签对顶点进行分组和计数。发出标记为'a'的副作用,这是按标签计算的组数。
==>[software:2,person:4]
gremlin> g.V().groupCount('a').by(label).groupCount('b').by(outE().count()).cap('a','b') //2.与语句1相同,但也会发出标记为'b'的副作用,该副作用按照出边的数量对顶点进行分组。
==>[a:[software:2,person:4],b:[0:3,1:1,2:1,3:1]]
Choose
- The choose():(分支)的路线横移到一个特定的遍历分支选项。
- 有了choose()它,就可以实现if / then / else-semantics以及更复杂的选择。
gremlin> g.V().hasLabel('person').
choose(values('age').is(lte(30)),
__.in(),
__.out()).values('name') //1.如果遍历产生一个元素,那么do in,else do out(即基于true / false的选项选择)。
==>marko
==>ripple
==>lop
==>lop
gremlin> g.V().hasLabel('person').
choose(values('age')).
option(27, __.in()).
option(32, __.out()).values('name') //2.使用遍历的结果作为遍历选项的映射关键(即基于值的选项选择)。
==>marko
==>ripple
==>lop
- 请注意,choose()可以有任意数量的选项,而且可以采用匿名遍历作为其选择功能。
gremlin> g.V().hasLabel('person').
choose(values('name')).
option('marko', values('age')).
option('josh', values('name')).
option('vadas', valueMap()).
option('peter', label())
==>29
==>[name:[vadas],age:[27]]
==>josh
==>person
- choose() 可以利用Pick.none选项匹配。对于与指定选项不匹配的任何内容,将采用none-option。
gremlin> g.V().hasLabel('person').
choose(values('name')).
option('marko', values('age')).
option(none, values('name'))
==>29
==>vadas
==>josh
==>peter
Coalesce 合并
- This coalesce(): 评估,以便所提供的遍历,并返回该发射的至少一种元素的第一遍历。
gremlin> g.V(1).coalesce(outE('knows'), outE('created')).inV().path().by('name').by(label)
==>[marko,knows,vadas]
==>[marko,knows,josh]
gremlin> g.V(1).coalesce(outE('created'), outE('knows')).inV().path().by('name').by(label)
==>[marko,created,lop]
gremlin> g.V(1).property('nickname', 'okram')
==>v[1]
gremlin> g.V().hasLabel('person').coalesce(values('nickname'), values('name'))
==>okram
==>vadas
==>josh
==>peter
Coin
- This coin():要随机筛选出一个遍历器.
- 提供的双重论点偏向于“掷硬币”。
gremlin> g.V().coin(0.5)
==>v[1]
==>v[2]
==>v[6]
gremlin> g.V().coin(0.0)
gremlin> g.V().coin(1.0)
==>v[1]
==>v[2]
==>v[3]
==>v[4]
==>v[5]
==>v[6]
Constant 常量
- This constant():要为移动器指定常量值
- 通常适用于像choose()-step或coalesce()-step这样的条件步骤。
gremlin> g.V().choose(hasLabel('person'),
values('name'),
constant('inhuman')) //1.显示人物的名字,但显示其他顶点的“inhuman”。
==>marko
==>vadas
==>inhuman
==>josh
==>inhuman
==>peter
gremlin> g.V().coalesce(
hasLabel('person').values('name'),
constant('inhuman')) //2.与陈述1相同(除非有没有名字的人顶点)。
==>marko
==>vadas
==>inhuman
==>josh
==>inhuman
==>peter
Count 计数
- This count():对在该流表示traversers的总数(即,批量计数)。
gremlin> g.V().count()
==>6
gremlin> g.V().hasLabel('person').count()
==>4
gremlin> g.V().hasLabel('person').outE('created').count().path() //1.count()-step是一个减少的屏障步骤,意味着所有以前的遍历器都被折叠成一个新的遍历器。
==>[4]
gremlin> g.V().hasLabel('person').outE('created').count().map {it.get() * 10}.path() //2.从... count()开始的移动器的路径从count()。
==>[4,40]
CyclicPath 循环路径
- 每个遍历器通过遍历图 - 即其路径来维护其历史。如果遍历器重复它的过程很重要,那么cyclic()应该使用-path(过滤器)
- 该步骤至此分析遍历器的路径,并且如果有任何重复,遍历器将在遍历计算中被滤除。如果需要非循环行为,请参阅simplePath()。
gremlin> g.V(1).both().both()
==>v[1]
==>v[4]
==>v[6]
==>v[1]
==>v[5]
==>v[3]
==>v[1]
gremlin> g.V(1).both().both().cyclicPath()
==>v[1]
==>v[1]
==>v[1]
gremlin> g.V(1).both().both().cyclicPath().path()
==>[v[1],v[3],v[1]]
==>[v[1],v[2],v[1]]
==>[v[1],v[4],v[1]]
gremlin> g.V(1).as('a').out('created').as('b').
in('created').as('c').
cyclicPath().
path()
==>[v[1],v[3],v[1]]
gremlin> g.V(1).as('a').out('created').as('b').
in('created').as('c').
cyclicPath().from('a').to('b').
path()
Dedup 删除重复
- This dedup():反复看到的对象将从遍历流中移除。
- 请注意,如果移动器的体积大于1,则在发射之前将其设置为1。
gremlin> g.V().values('lang')
==>java
==>java
gremlin> g.V().values('lang').dedup()
==>java
gremlin> g.V(1).repeat(bothE('created').dedup().otherV()).emit().path() //1。遍历所有created边,但不要碰两边。
==>[v[1],e[9][1-created->3],v[3]]
==>[v[1],e[9][1-created->3],v[3],e[11][4-created->3],v[4]]
==>[v[1],e[9][1-created->3],v[3],e[12][6-created->3],v[6]]
==>[v[1],e[9][1-created->3],v[3],e[11][4-created->3],v[4],e[10][4-created->5],v[5]]
- 如果提供了逐步调制dedup(),则在确定是否已经看到对象之前对该对象进行相应处理。
gremlin> g.V().valueMap(true, 'name')
==>[id:1,name:[marko],label:person]
==>[id:2,name:[vadas],label:person]
==>[id:3,name:[lop],label:software]
==>[id:4,name:[josh],label:person]
==>[id:5,name:[ripple],label:software]
==>[id:6,name:[peter],label:person]
gremlin> g.V().dedup().by(label).values('name')
==>marko
==>lop
- 如果dedup()提供了一个字符串数组,那么它将确保重复数据删除不是针对当前的遍历器对象,而是针对遍历器的路径历史记录。
gremlin> g.V().as('a').out('created').as('b').in('created').as('c').select('a','b','c')
==>[a:v[1],b:v[3],c:v[1]]
==>[a:v[1],b:v[3],c:v[4]]
==>[a:v[1],b:v[3],c:v[6]]
==>[a:v[4],b:v[5],c:v[4]]
==>[a:v[4],b:v[3],c:v[1]]
==>[a:v[4],b:v[3],c:v[4]]
==>[a:v[4],b:v[3],c:v[6]]
==>[a:v[6],b:v[3],c:v[1]]
==>[a:v[6],b:v[3],c:v[4]]
==>[a:v[6],b:v[3],c:v[6]]
gremlin> g.V().as('a').out('created').as('b').in('created').as('c').dedup('a','b').select('a','b','c') //1。如果之前已经看到电流a和b组合,则过滤移动器。
==>[a:v[1],b:v[3],c:v[1]]
==>[a:v[4],b:v[5],c:v[4]]
==>[a:v[4],b:v[3],c:v[1]]
==>[a:v[6],b:v[3],c:v[1]]
Drop 下降
- This drop():用于除去从所述图形元素和属性(即删除)。
- 这是一个过滤步骤,因为遍历不会产生传出对象。
gremlin> g.V().outE().drop()
gremlin> g.E()
gremlin> g.V().properties('name').drop()
gremlin> g.V().valueMap()
==>[age:[29]]
==>[age:[27]]
==>[lang:[java]]
==>[age:[32]]
==>[lang:[java]]
==>[age:[35]]
gremlin> g.V().drop()
gremlin> g.V()
Emit
- This emit():不是实际的一步,但不是为一个步调制器repeat()(找到更多的文档emit()存在)。
Explain 解释
- This explain():(终端)将返回一个TraversalExplanation。
- 遍历解释详细说明了遍历(之前explain())将如何在给定注册遍历策略的情况下编译。
- A TraversalExplanation具有toString()3列的表示。
- 第一列是应用的遍历策略。
- 第二列是遍历策略类别:[D]生态化,[O]优化,[P]漫游器优化,[F]实现和[V]验证。
- 最后,第三列是遍历后策略应用程序的状态。最后的遍历是由此产生的执行计划。
gremlin> g.V().hasLabel('person').outE().identity().inV().count().is(gt(5)).explain()
==>Traversal Explanation
=====================================================================================================================================================================================================
Original Traversal [GraphStep(vertex,[]), HasStep([~label.eq(person)]), VertexStep(OUT,edge), IdentityStep, EdgeVertexStep(IN), CountGlobalStep, IsStep(gt(5))]
ConnectiveStrategy [D] [GraphStep(vertex,[]), HasStep([~label.eq(person)]), VertexStep(OUT,edge), IdentityStep, EdgeVertexStep(IN), CountGlobalStep, IsStep(gt(5))]
RepeatUnrollStrategy [O] [GraphStep(vertex,[]), HasStep([~label.eq(person)]), VertexStep(OUT,edge), IdentityStep, EdgeVertexStep(IN), CountGlobalStep, IsStep(gt(5))]
IncidentToAdjacentStrategy [O] [GraphStep(vertex,[]), HasStep([~label.eq(person)]), VertexStep(OUT,edge), IdentityStep, EdgeVertexStep(IN), CountGlobalStep, IsStep(gt(5))]
MatchPredicateStrategy [O] [GraphStep(vertex,[]), HasStep([~label.eq(person)]), VertexStep(OUT,edge), IdentityStep, EdgeVertexStep(IN), CountGlobalStep, IsStep(gt(5))]
PathRetractionStrategy [O] [GraphStep(vertex,[]), HasStep([~label.eq(person)]), VertexStep(OUT,edge), IdentityStep, EdgeVertexStep(IN), CountGlobalStep, IsStep(gt(5))]
CountStrategy [O] [GraphStep(vertex,[]), HasStep([~label.eq(person)]), VertexStep(OUT,edge), IdentityStep, EdgeVertexStep(IN), RangeGlobalStep(0,6), CountGlobalStep, IsStep(gt(5))]
FilterRankingStrategy [O] [GraphStep(vertex,[]), HasStep([~label.eq(person)]), VertexStep(OUT,edge), IdentityStep, EdgeVertexStep(IN), RangeGlobalStep(0,6), CountGlobalStep, IsStep(gt(5))]
InlineFilterStrategy [O] [GraphStep(vertex,[]), HasStep([~label.eq(person)]), VertexStep(OUT,edge), IdentityStep, EdgeVertexStep(IN), RangeGlobalStep(0,6), CountGlobalStep, IsStep(gt(5))]
AdjacentToIncidentStrategy [O] [GraphStep(vertex,[]), HasStep([~label.eq(person)]), VertexStep(OUT,edge), IdentityStep, EdgeVertexStep(IN), RangeGlobalStep(0,6), CountGlobalStep, IsStep(gt(5))]
LazyBarrierStrategy [O] [GraphStep(vertex,[]), HasStep([~label.eq(person)]), VertexStep(OUT,edge), IdentityStep, EdgeVertexStep(IN), RangeGlobalStep(0,6), CountGlobalStep, IsStep(gt(5))]
TinkerGraphCountStrategy [P] [GraphStep(vertex,[]), HasStep([~label.eq(person)]), VertexStep(OUT,edge), IdentityStep, EdgeVertexStep(IN), RangeGlobalStep(0,6), CountGlobalStep, IsStep(gt(5))]
TinkerGraphStepStrategy [P] [TinkerGraphStep(vertex,[~label.eq(person)]), VertexStep(OUT,edge), IdentityStep, EdgeVertexStep(IN), RangeGlobalStep(0,6), CountGlobalStep, IsStep(gt(5))]
ProfileStrategy [F] [TinkerGraphStep(vertex,[~label.eq(person)]), VertexStep(OUT,edge), IdentityStep, EdgeVertexStep(IN), RangeGlobalStep(0,6), CountGlobalStep, IsStep(gt(5))]
StandardVerificationStrategy [V] [TinkerGraphStep(vertex,[~label.eq(person)]), VertexStep(OUT,edge), IdentityStep, EdgeVertexStep(IN), RangeGlobalStep(0,6), CountGlobalStep, IsStep(gt(5))]
Final Traversal [TinkerGraphStep(vertex,[~label.eq(person)]), VertexStep(OUT,edge), IdentityStep, EdgeVertexStep(IN), RangeGlobalStep(0,6), CountGlobalStep, IsStep(gt(5))]
Fold 折叠
- 遍历流需要一个“屏障”来聚合所有对象并发出一个计算函数作为聚合函数
gremlin> g.V(1).out('knows').values('name')
==>vadas
==>josh
gremlin> g.V(1).out('knows').values('name').fold() //1。无参数fold()会将所有对象聚合到列表中,然后发出列表。
==>[vadas,josh]
gremlin> g.V(1).out('knows').values('name').fold().next().getClass() //2。无参数fold()会将所有对象聚合到列表中,然后发出列表。
==>class java.util.ArrayList
gremlin> g.V(1).out('knows').values('name').fold(0) {a,b -> a + b.length()} //3。fold() 可以提供两个参数 - 一个种子值和一个减少双向函数(“vadas”是5个字符+“josh”,4个字符)。
==>9
gremlin> g.V().values('age').fold(0) {a,b -> a + b} //4。图中人的总年龄是多少?
==>123
gremlin> g.V().values('age').fold(0, sum) //5。与以前一样,但使用内置的双功能。
==>123
gremlin> g.V().values('age').sum() //6。与以前一样,但使用内置的双功能。
==>123
From
- This from():不是一个实际的步骤,而是一个类似于as()和 的“阶跃调节器” by()。
- 如果一个步骤能够接受遍历或字符串,那么from()它们就是添加它们的手段。一般模式是step().from()。见 - to()步。
gremlin> g.V().has('name', within('marko', 'vadas', 'josh')).as('person').
V().has('name', within('lop', 'ripple')).addE('uses').from('person')
==>e[13][1-uses->3]
==>e[14][1-uses->5]
==>e[15][2-uses->3]
==>e[16][2-uses->5]
==>e[17][4-uses->3]
==>e[18][4-uses->5]
Graph
- This graph():通常用于启动GraphTraversal,但也可以使用中间穿越。
remlin> g.V().has('name', within('marko', 'vadas', 'josh')).as('person').
V().has('name', within('lop', 'ripple')).addE('uses').from('person').toString() //1。通常这个步骤V()将遍历所有的顶点。但是,图策略可以折叠HasContainer’s into a `GraphStep以允许索引查找。
==>[GraphStep(vertex,[]), HasStep([name.within([marko, vadas, josh])])@[person], GraphStep(vertex,[]), HasStep([name.within([lop, ripple])]), AddEdgeStep({~from=[[SelectOneStep(last,person)]], label=[uses]})]
gremlin> g.V().has('name', within('marko', 'vadas', 'josh')).as('person').
V().has('name', within('lop', 'ripple')).addE('uses').from('person').iterate().toString() //2。图形系统提供者是否支持中间遍历V()索引查找可以通过检查toString()迭代遍历的输出来轻松确定。如果has条件被折叠成步骤,则将V()使用索引(如果存在的话)。
==>[TinkerGraphStep(vertex,[name.within([marko, vadas, josh])])@[person], TinkerGraphStep(vertex,[name.within([lop, ripple])]), AddEdgeStep({~from=[[SelectOneStep(last,person)]], label=[uses]}), NoneStep]
Group 组
- 当遍历器遍历一个由遍历定义的图时,有时需要sideEffect计算。
- 也就是说,所采用的实际路径或者移动器的当前位置不是计算的最终输出,而是遍历的一些其他表示。
- 所述group()工序(地图 / sideEffect)就是这样一种sideEffect,根据对象的某些功能组织的对象。然后,如果需要,该组织(列表)将减少。
gremlin> g.V().group().by(label) //1.按照它们的标签对顶点进行分组。
==>[software:[v[3],v[5]],person:[v[1],v[2],v[4],v[6]]]
gremlin> g.V().group().by(label).by('name') //2.对于组中的每个顶点,获取它们的名称。
==>[software:[lop,ripple],person:[marko,vadas,josh,peter]]
gremlin> g.V().group().by(label).by(count()) //3.对于每个分组,它的大小是多少?
==>[software:2,person:4]
可以group()通过的两个投影参数by()是:
Key-projection:组合对象的哪个特征(产生map键的函数)
价值投影:该组的哪些功能要存储在密钥列表中
GroupCount 分组统计
- This groupCount():特定对象在遍历的特定部分有多少次
gremlin> g.V().hasLabel('person').values('age').groupCount()
==>[32:1,35:1,27:1,29:1]
gremlin> g.V().hasLabel('person').groupCount().by('age') //1.您还可以提供预组投影,其中提供的by()调制决定了将传入对象分组的内容。
==>[32:1,35:1,27:1,29:1]
Has 有
This has():根据其属性过滤顶点,边和顶点属性。有很多变化,has()包括:
has(key,value):如果元素没有提供的键/值属性,则移除该移动器。
has(label, key, value):如果元素没有指定的标签并提供键/值属性,则移除该移动器。
has(key,predicate):如果元素没有满足双谓词的键值,则移除该移动器。有关谓词的更多信息,请阅读关于谓词的注释。
hasLabel(labels…):如果元素没有任何标签,则移除移动器。
hasId(ids…):如果元素没有任何id,则移除移动器。
hasKey(keys…):如果属性没有提供所有提供的键,则移除移动器。
hasValue(values…):如果移动器的属性没有提供所有提供的值,则移除移动器。
has(key):如果移动元素的元素没有键值,则移除移动元素。
hasNot(key):如果元素的值为该键,则移除该移动器。
has(key, traversal):如果移动器的对象没有通过遍历属性值产生结果,则移除移动器。
gremlin> g.V().hasLabel('person')
==>v[1]
==>v[2]
==>v[4]
==>v[6]
gremlin> g.V().hasLabel('person').out().has('name',within('vadas','josh'))
==>v[2]
==>v[4]
gremlin> g.V().hasLabel('person').out().has('name',within('vadas','josh')).
outE().hasLabel('created')
==>e[10][4-created->5]
==>e[11][4-created->3]
gremlin> g.V().has('age',inside(20,30)).values('age') //1.查找年龄在20(含)和30(不含)之间的所有顶点。
==>29
==>27
gremlin> g.V().has('age',outside(20,30)).values('age') //2.查找年龄不在20(含)和30(不含)之间的所有顶点。
==>32
==>35
gremlin> g.V().has('name',within('josh','marko')).valueMap() //3.查找名称完全匹配集合中任何名称的所有顶点[josh,marko],显示这些顶点的所有键和值对。
==>[name:[marko],age:[29]]
==>[name:[josh],age:[32]]
gremlin> g.V().has('name',without('josh','marko')).valueMap() //4.查找名称不在集合中的所有顶点[josh,marko],显示这些顶点的所有键,值对。对。
==>[name:[vadas],age:[27]]
==>[name:[lop],lang:[java]]
==>[name:[ripple],lang:[java]]
==>[name:[peter],age:[35]]
gremlin> g.V().has('name',not(within('josh','marko'))).valueMap() //5.和前面的例子一样,使用noton within来保存without。
==>[name:[vadas],age:[27]]
==>[name:[lop],lang:[java]]
==>[name:[ripple],lang:[java]]
==>[name:[peter],age:[35]]
gremlin> g.V().properties().hasKey('age').value() //6.查找所有年龄属性并发布其价值。
==>29
==>27
==>32
==>35
gremlin> g.V().hasNot('age').values('name') //7.查找所有没有年龄属性并发出其名称的顶点。
==>lop
==>ripple
Id
- 接受一个Element,并从中提取其标识符。
gremlin> g.V().id()
==>1
==>2
==>3
==>4
==>5
==>6
gremlin> g.V(1).out().id().is(2)
==>2
gremlin> g.V(1).outE().id()
==>9
==>7
==>8
gremlin> g.V(1).properties().id()
==>0
==>1
Identity 恒定
- This identity():是恒等函数,其中当前对象映射到其自身。
gremlin> g.V().identity()
==>v[1]
==>v[2]
==>v[3]
==>v[4]
==>v[5]
==>v[6]
Inject 注入
- This inject():将对象任意插入到遍历流中
gremlin> g.V(4).out().values('name').inject('daniel')
==>daniel
==>ripple
==>lop
gremlin> g.V(4).out().values('name').inject('daniel').map {it.get().length()}
==>6
==>6
==>3
gremlin> g.V(4).out().values('name').inject('daniel').map {it.get().length()}.path()
==>[daniel,6]
==>[v[4],v[5],ripple,6]
==>[v[4],v[3],lop,3]
Is 是
- This is():过滤标量值
gremlin> g.V().values('age').is(32)
==>32
gremlin> g.V().values('age').is(lte(30))
==>29
==>27
gremlin> g.V().values('age').is(inside(30, 40))
==>32
==>35
gremlin> g.V().where(__.in('created').count().is(1)).values('name') //1.查找只有一个贡献者的项目。
==>ripple
gremlin> g.V().where(__.in('created').count().is(gte(2))).values('name') //2.查找有两个或更多贡献者的项目。
==>lop
gremlin> g.V().where(__.in('created').values('age').
mean().is(inside(30d, 35d))).values('name') //3.查找贡献者平均年龄在30岁到35岁之间的项目。
==>lop
==>ripple
Key 键
- This key():需要Property,并从中提取的关键。
gremlin> g.V(1).properties().key()
==>name
==>location
==>location
==>location
==>location
gremlin> g.V(1).properties().properties().key()
==>startTime
==>endTime
==>startTime
==>endTime
==>startTime
==>endTime
==>startTime
Label 标签
- 需要一个Element并从中提取其标签。
gremlin> g.V().label()
==>person
==>person
==>software
==>person
==>software
==>person
gremlin> g.V(1).outE().label()
==>created
==>knows
==>knows
gremlin> g.V(1).properties().label()
==>name
==>age
Limit 限制
- 类似于range()-步骤保存的下端范围被设定为0。
gremlin> g.V().limit(2)
==>v[1]
==>v[2]
gremlin> g.V().range(0, 2)
==>v[1]
==>v[2]
- 这个步骤limit()也可以应用Scope.local,在这种情况下,它在收到的收集上运行。
gremlin> g.V().valueMap().select('location').limit(local,2) //1.List<String> 对于包含前两个位置的每个顶点。
==>[san diego,santa cruz]
==>[centreville,dulles]
==>[bremen,baltimore]
==>[spremberg,kaiserslautern]
gremlin> g.V().valueMap().limit(local, 1) //2.Map<String, Object> 为每个顶点,但只包含第一个属性值。
==>[name:[marko]]
==>[name:[stephen]]
==>[name:[matthias]]
==>[name:[daniel]]
==>[name:[gremlin]]
==>[name:[tinkergraph]]
Local 本地
- A GraphTraversal在连续的对象流上运行。
- 在很多情况下,在该流内的单个元素上操作非常重要。为了做这种对象局部遍历计算
gremlin> g.V().as('person').
properties('location').order().by('startTime',incr).limit(2).value().as('location').
select('person','location').by('name').by() //1.根据历史最悠久的地点开始时间获取前两个人和他们各自的位置。
==>[person:daniel,location:spremberg]
==>[person:stephen,location:centreville]
gremlin> g.V().as('person').
local(properties('location').order().by('startTime',incr).limit(2)).value().as('location').
select('person','location').by('name').by() //2.对于每个人来说,他们的两个最具历史意义的地点
==>[person:marko,location:san diego]
==>[person:marko,location:santa cruz]
==>[person:stephen,location:centreville]
==>[person:stephen,location:dulles]
==>[person:matthias,location:bremen]
==>[person:matthias,location:baltimore]
==>[person:daniel,location:spremberg]
==>[person:daniel,location:kaiserslautern]
Loops 循环
- This loops():提取的次数的数目Traverser已经通过电流环路消失。
remlin> g.V().emit(__.has("name", "marko").or().loops().is(2)).repeat(__.out()).values("name")
==>marko
==>ripple
==>lop
Match 匹配
- 提供了一个更加声明 基于的概念图表查询的形式图案匹配。
- 用户提供了一组“遍历碎片”,称为模式,它们定义了必须在整个持续时间内保持为真的变量match()。
- 当一个遍历器进入时match(),一个注册 MatchAlgorithm分析遍历器的当前状态(也就是基于其路径数据的历史 ),遍历模式的运行时统计信息,并返回遍历器应该接下来尝试的遍历模式。
- MatchAlgorithm提供的默认值被调用CountMatchAlgorithm并且它通过根据模式的过滤能力对模式进行排序来动态修改模式执行计划(即,最大集合缩减模式首先执行)。
gremlin> g.V().match(
__.as('a').out('created').as('b'),
__.as('b').has('name', 'lop'),
__.as('b').in('created').as('c'),
__.as('c').has('age', 29)).
select('a','c').by('name')
==>[a:marko,c:marko]
==>[a:josh,c:marko]
==>[a:peter,c:marko]
- 为了提高可读性,as()可以为步骤提供有意义的标签,以更好地反映您的域名。因此,以前的查询可以用更具表现力的方式编写,如下所示。
gremlin> g.V().match(
__.as('creators').out('created').has('name', 'lop').as('projects'), //1.找到创建东西的顶点并将它们匹配为“创建者”,然后找出他们创建的名为“lop”并将这些顶点匹配为“项目”的顶点。
__.as('projects').in('created').has('age', 29).as('cocreators')). //2.使用这些'项目'顶点,找出他们的创作者29岁,并记住这些'共同创作者'。
select('creators','cocreators').by('name') //3.返回'创作者'和'共同创作者'的名字。
==>[creators:marko,cocreators:marko]
==>[creators:josh,cocreators:marko]
==>[creators:peter,cocreators:marko]
使用匹配的地方
- 匹配通常与两者select()(先前演示)和where()(在此展示)一起使用。
- A- where()step允许用户进一步限制由提供的结果集match()。
gremlin> g.V().match(
__.as('a').out('created').as('b'),
__.as('b').in('created').as('c')).
where('a', neq('c')).
select('a','c').by('name')
==>[a:marko,c:josh]
==>[a:marko,c:peter]
==>[a:josh,c:marko]
==>[a:josh,c:peter]
==>[a:peter,c:marko]
==>[a:peter,c:josh]
- where()-步骤可以采取任一个P-predicate(例如上文)或一个Traversal(下面例子)。使用时 MatchPredicateStrategy,where()-clauses自动折叠match(),因此受制于查询优化器match()。
gremlin> traversal = g.V().match(
__.as('a').has(label,'person'), //1\
__.as('a').out('created').as('b'),
__.as('b').in('created').as('c')).
where(__.as('a').out('knows').as('c')). //2\
select('a','c').by('name'); null //3\
gremlin> traversal.toString() //4\
==>[GraphStep(vertex,[]), MatchStep(AND,[[MatchStartStep(a), HasStep([~label.eq(person)]), MatchEndStep], [MatchStartStep(a), VertexStep(OUT,[created],vertex), MatchEndStep(b)], [MatchStartStep(b), VertexStep(IN,[created],vertex), MatchEndStep(c)]]), WhereTraversalStep([WhereStartStep(a), VertexStep(OUT,[knows],vertex), WhereEndStep(c)]), SelectStep(last,[a, c],[value(name)])]
gremlin> traversal // (5)
==>[a:marko,c:josh]
gremlin> traversal.toString() //7\
==>[TinkerGraphStep(vertex,[~label.eq(person)])@[a], MatchStep(AND,[[MatchStartStep(a), VertexStep(OUT,[created],vertex), MatchEndStep(b)], [MatchStartStep(b), VertexStep(IN,[created],vertex), MatchEndStep(c)], [MatchStartStep(a), WhereTraversalStep([WhereStartStep, VertexStep(OUT,[knows],vertex), WhereEndStep(c)]), MatchEndStep]]), SelectStep(last,[a, c],[value(name)])]
Math
- 科学计算器功能
gremlin> g.V().as('a').out('knows').as('b').math('a + b').by('age')
==>56.0
==>61.0
gremlin> g.V().as('a').out('created').as('b').
math('b + a').
by(both().count().math('_ + 100')).
by('age')
==>132.0
==>133.0
==>135.0
==>138.0
gremlin> g.withSideEffect('x',10).V().values('age').math('_ / x')
==>2.9
==>2.7
==>3.2
==>3.5
gremlin> g.withSack(1).V(1).repeat(sack(sum).by(constant(1))).times(10).emit().sack().math('sin _')
==>0.9092974268256817
==>0.1411200080598672
==>-0.7568024953079282
==>-0.9589242746631385
==>-0.27941549819892586
==>0.6569865987187891
==>0.9893582466233818
==>0.4121184852417566
==>-0.5440211108893698
==>-0.9999902065507035
通过计算器支持的运营商包括:*,+,\,^,和%。此外,还提供了以下内置功能:
abs: 绝对值
acos:反余弦
asin:反正弦
atan:反正切
cbrt:立方根
ceil:最接近的大整数
cos:余弦
cosh:双曲余弦
exp:欧拉的号码提升到了力量(e^x)
floor:最接近的较小整数
log:logarithmus naturalis(基数e)
log10:对数(基数10)
log2:对数(基数2)
sin:正弦
sinh:双曲正弦
sqrt: 平方根
tan:切线
tanh:双曲正切
signum:signum函数
Max
- 最大值
gremlin> g.V().values('age').max()
==>35
gremlin> g.V().repeat(both()).times(3).values('age').max()
==>35
Mean 平均值
- 操作数的流,并确定这些数字的平均值。
gremlin> g.V().values('age').mean()
==>30.75
gremlin> g.V().repeat(both()).times(3).values('age').mean() //1\
==>30.645833333333332
gremlin> g.V().repeat(both()).times(3).values('age').dedup().mean()
==>30.75
Min 最小值
- 操作数的流,并确定它是在流中的最小数目。
gremlin> g.V().values('age').min()
==>27
gremlin> g.V().repeat(both()).times(3).values('age').min()
==>27
Not
- (过滤器时遍历提供作为参数不返回任何对象)去除遍历流对象。
gremlin> g.V().not(hasLabel('person')).valueMap(true)
==>[id:3,name:[lop],label:software,lang:[java]]
==>[id:5,name:[ripple],label:software,lang:[java]]
gremlin> g.V().hasLabel('person').
not(out('created').count().is(gt(1))).values('name') //1.乔什创建了两个项目,而没有任何项目
==>marko
==>vadas
==>peter
Option
- An option to a branch() or choose().
Optional
- 如果它产生的结果,否则返回调用元件
- 返回指定遍历的结果identity()。
gremlin> g.V(2).optional(out('knows')) //1.vadas没有离开的知识边缘,所以vadas被返回。
==>v[2]
gremlin> g.V(2).optional(__.in('knows')) //2.vadas确实有一个传入知识边缘,所以marko被返回。
==>v[1]
Or 或者
- This or():确保了提供遍历中的至少一个产生的结果
gremlin> g.V().or(
__.outE('created'),
__.inE('created').count().is(gt(1))).
values('name')
==>marko
==>lop
==>josh
==>peter
- 一个中间符号可以被使用。尽管用中缀表示法,只有两次遍历可以在一起。
gremlin> g.V().where(outE('created').or().outE('knows')).values('name')
==>marko
==>josh
==>peter
Order 排序
- 当遍历流的对象需要排序时
gremlin> g.V().values('name').order()
==>josh
==>lop
==>marko
==>peter
==>ripple
==>vadas
gremlin> g.V().values('name').order().by(decr)
==>vadas
==>ripple
==>peter
==>marko
==>lop
==>josh
gremlin> g.V().hasLabel('person').order().by('age', incr).values('name')
==>vadas
==>marko
==>josh
==>peter
- 遍历中最遍历的对象之一是Element。元素可以具有与其关联的属性(即键/值对)。在许多情况下,需要根据元素属性的比较对元素遍历流进行排序。
gremlin> g.V().values('name')
==>marko
==>vadas
==>lop
==>josh
==>ripple
==>peter
gremlin> g.V().order().by('name',incr).values('name')
==>josh
==>lop
==>marko
==>peter
==>ripple
==>vadas
gremlin> g.V().order().by('name',decr).values('name')
==>vadas
==>ripple
==>peter
==>marko
==>lop
==>josh
- 可以用来order(local)排序当前的本地对象,而不是整个遍历流。这适用于 Collection- 和Map- 类型的对象。对于任何其他对象,该对象将保持不变。
gremlin> g.V().values('age').fold().order(local).by(decr) //1。年龄被收集到一个列表中,然后该列表按降序排列。
==>[35,32,29,27]
gremlin> g.V().values('age').order(local).by(decr) //2。年龄不收集,因此order(local)是“排序”单个整数,因此,什么都不做。
==>29
==>27
==>32
==>35
gremlin> g.V().groupCount().by(inE().count()).order(local).by(values, decr) //3。该groupCount()地图是由它的递减顺序值进行排序。
==>[1:3,0:2,3:1]
gremlin> g.V().groupCount().by(inE().count()).order(local).by(keys, incr) //4。该groupCount()图是通过其在递增的顺序排列的键。
==>[0:2,1:3,3:1]
Path 路径
- 遍历器在遍历中的一系列步骤中进行转换。遍历器的历史通过用path()-step(地图)检查其路径来实现。
gremlin> g.V().out().out().values('name')
==>ripple
==>lop
gremlin> g.V().out().out().values('name').path()
==>[v[1],v[4],v[5],ripple]
==>[v[1],v[4],v[3],lop]
- 可以通过循环方式后处理路径的元素by()。
gremlin> g.V().out().out().path().by('name').by('age')
==>[marko,32,ripple]
==>[marko,32,lop]
Profile
- 为了让开发者介绍他们的遍历,以确定像步运行,计数等统计信息
gremlin> g.V().out('created').repeat(both()).times(3).hasLabel('person').values('age').sum().profile()
==>Traversal Metrics
Step Count Traversers Time (ms) % Dur
=============================================================================================================
TinkerGraphStep(vertex,[]) 6 6 0.076 11.61
VertexStep(OUT,[created],vertex) 4 4 0.108 16.39
NoOpBarrierStep(2500) 4 2 0.050 7.63
VertexStep(BOTH,vertex) 10 4 0.045 6.86
NoOpBarrierStep(2500) 10 3 0.025 3.81
VertexStep(BOTH,vertex) 24 7 0.028 4.34
NoOpBarrierStep(2500) 24 5 0.030 4.62
VertexStep(BOTH,vertex) 58 11 0.040 6.15
NoOpBarrierStep(2500) 58 6 0.046 7.03
HasStep([~label.eq(person)]) 48 4 0.033 5.08
PropertiesStep([age],value) 48 4 0.042 6.37
SumGlobalStep 1 1 0.133 20.11
>TOTAL - - 0.662 -
Project
- 突出的当前对象到Map
gremlin> g.V().out('created').
project('a','b').
by('name').
by(__.in('created').count()).
order().by(select('b'),decr).
select('a')
==>lop
==>lop
==>lop
==>ripple
gremlin> g.V().has('name','marko').
project('out','in').
by(outE().count()).
by(inE().count())
==>[out:3,in:0]
Program
- 是“lambda”步骤GraphComputer的作业。
- 该步骤将 VertexProgram作为参数并相应地处理传入图。
因此,用户可以创建自己的VertexProgram并在遍历中执行它。提供给顶点程序的配置包括:
gremlin.vertexProgramStep.rootTraversal是PureTraversal根遍历的一种形式的序列化。
gremlin.vertexProgramStep.stepId是program()正在执行的-step 的步骤字符串id 。
gremlin> g = graph.traversal().withComputer()
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], graphcomputer]
gremlin> g.V().hasLabel('person').
program(PageRankVertexProgram.build().property('rank').create(graph)).
order().by('rank', incr).
valueMap('name', 'rank')
==>[name:[marko],rank:[0.11375510357865541]]
==>[name:[peter],rank:[0.11375510357865541]]
==>[name:[vadas],rank:[0.14598540152719106]]
==>[name:[josh],rank:[0.14598540152719106]]
Properties 属性
- 提取属性Element遍历流。
gremlin> g.V(1).properties()
==>vp[name->marko]
==>vp[location->san diego]
==>vp[location->santa cruz]
==>vp[location->brussels]
==>vp[location->santa fe]
gremlin> g.V(1).properties('location').valueMap()
==>[startTime:1997,endTime:2001]
==>[startTime:2001,endTime:2004]
==>[startTime:2004,endTime:2005]
==>[startTime:2005]
gremlin> g.V(1).properties('location').has('endTime').valueMap()
==>[startTime:1997,endTime:2001]
==>[startTime:2001,endTime:2004]
==>[startTime:2004,endTime:2005]
PropertyMap
- 步骤产生一个元素的属性的地图表示
gremlin> g.V().propertyMap()
==>[name:[vp[name->marko]],age:[vp[age->29]]]
==>[name:[vp[name->vadas]],age:[vp[age->27]]]
==>[name:[vp[name->lop]],lang:[vp[lang->java]]]
==>[name:[vp[name->josh]],age:[vp[age->32]]]
==>[name:[vp[name->ripple]],lang:[vp[lang->java]]]
==>[name:[vp[name->peter]],age:[vp[age->35]]]
gremlin> g.V().propertyMap('age')
==>[age:[vp[age->29]]]
==>[age:[vp[age->27]]]
==>[]
==>[age:[vp[age->32]]]
==>[]
==>[age:[vp[age->35]]]
gremlin> g.V().propertyMap('age','blah')
==>[age:[vp[age->29]]]
==>[age:[vp[age->27]]]
==>[]
==>[age:[vp[age->32]]]
==>[]
==>[age:[vp[age->35]]]
gremlin> g.E().propertyMap()
==>[weight:p[weight->0.5]]
==>[weight:p[weight->1.0]]
==>[weight:p[weight->0.4]]
==>[weight:p[weight->1.0]]
==>[weight:p[weight->0.4]]
==>[weight:p[weight->0.2]]
Range
- This range():当遍历器通过遍历传播时,可能只允许一定数量的它们通过.
- 当范围的低端不符合时,对象继续迭代。在低(包含)和高(独占)范围内,发射移动器。当在高范围以上时,遍历就会脱离迭代。最后,-1高范围的使用将在低范围开始后发射剩余的移动器。
gremlin> g.V().range(0,3)
==>v[1]
==>v[2]
==>v[3]
gremlin> g.V().range(1,3)
==>v[2]
==>v[3]
gremlin> g.V().range(1, -1)
==>v[2]
==>v[3]
==>v[4]
==>v[5]
==>v[6]
gremlin> g.V().repeat(both()).times(1000000).emit().range(6,10)
==>v[1]
==>v[5]
==>v[3]
==>v[1]
- range()也可以应用Scope.local,在这种情况下,它在收到的收集上运行。例如,可以Map
gremlin> g.V().as('a').out().as('b').in().as('c').select('a','b','c').by('name').range(local,1,2)
==>[b:lop]
==>[b:lop]
==>[b:lop]
==>[b:vadas]
==>[b:josh]
==>[b:ripple]
==>[b:lop]
==>[b:lop]
==>[b:lop]
==>[b:lop]
==>[b:lop]
==>[b:lop]
Repeat
- 用于遍历给予一定的休息谓词遍历。
gremlin> g.V(1).repeat(out()).times(2).path().by('name') //1.do-while semantics stating to do out() 2 times.
==>[marko,josh,ripple]
==>[marko,josh,lop]
gremlin> g.V().until(has('name','ripple')).
repeat(out()).path().by('name') //2.while-do语义如果遍历器位于名为“ripple”的顶点,则声明为中断。
==>[marko,josh,ripple]
==>[josh,ripple]
==>[ripple]