48 Project Step
project()
步驟(map)將當前對象投射到由提供的標簽鍵入的Map<String,Object>
中。
gremlin> g.V().out('created').
project('a','b').
by('name').
by(__.in('created').count())
==>[a:lop,b:3]
==>[a:lop,b:3]
==>[a:lop,b:3]
==>[a:ripple,b:1]
使用該步驟,可以提供靈活的方式進行遍歷的調整。如根據(工程)創建者的人數進行排序,並返回(工程)的名字:
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
49 Program Step
program()
- 步驟(map / sideEffect)是GraphComputer作業的“lambda”步驟。該步驟將使用VertexProgram作為參數,並相應地處理傳入圖形。因此,用戶可以創建自己的VertexProgram並使其在遍歷中執行。
比如,使用PageRankVertexProgram
計算PageRank,並降序排列:
gremlin> g = graph.traversal().withComputer()
gremlin> g.V().program(PageRankVertexProgram.build().property('rank').create(graph)).
order().by('rank', decr).
valueMap('name', 'rank')
==>[name:[lop],rank:[0.4018125]]
==>[name:[ripple],rank:[0.23181250000000003]]
==>[name:[vadas],rank:[0.19250000000000003]]
==>[name:[josh],rank:[0.19250000000000003]]
==>[name:[marko],rank:[0.15000000000000002]]
==>[name:[peter],rank:[0.15000000000000002]]
Note
開發VertexProgram是專家用戶,需要對OLAP有深入研究。
50 Properties Step
properties()
步驟(map)從遍歷流中的Element中提取屬性。
gremlin> g.V().properties()
==>vp[name->marko]
==>vp[age->29]
==>vp[name->lop]
==>vp[lang->java]
==>vp[name->vadas]
==>vp[age->27]
==>vp[name->josh]
==>vp[age->32]
==>vp[name->ripple]
==>vp[lang->java]
==>vp[name->peter]
==>vp[age->35]
51 PropertyMap Step
propertiesMap()
- 步驟產生元素屬性的Map表示。
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]]]
52 Range Step
range()
步驟(filter)用於指定范圍。
如返回第0/1/2個頂點:
gremlin> g.V().range(0,3) //返回位置在[0,3)即0,1,2的節點
==>v[1]
==>v[3]
==>v[2]
53 Repeat Step
`repeat()·步驟(branch)會根據給定的謂詞(predicate)進行循環遍歷。
如以下語句產生相同的結果:
gremlin> g.V(1).out().out().values('name')
==>ripple
==>lop
gremlin> g.V(1).repeat(out()).times(2).values('name')
==>ripple
==>lop
- 發現兩個節點之間存在的關系
從id為1的節點開始向外發現關系,直至發現name=ripple
的節點,輸出所遍歷路徑上節點的名字:
gremlin> g.V(1).until(has('name','ripple')).repeat(out()).path().by('name')
==>[marko,josh,ripple]
repeat()
有兩個調制器:until()
和emit()
。
until()
如果until()
在repeat()
之后出現,則是do/while循環。如果until()
在repeat()
之前出現,則是while/do循環。emit()
如果在repeat()
之后放置emit()
,則對遍歷遍歷器進行重復遍歷評估。如果將emit()
放在repeat()
之前,則在進入重復遍歷之前對遍歷器進行求值。
除了emit()
位置不同造成的影響外,emit()
還使得repeat()
中每次循環都會輸出。
gremlin> g.V(1).repeat(out()).times(2).values('name') //兩次循環完后的節點
==>ripple
==>lop
gremlin> g.V(1).repeat(out()).emit().times(2).values('name') //一次循環和兩次循環結果都返回
==>lop
==>vadas
==>josh
==>ripple
==>lop
gremlin> g.V(1).emit().repeat(out()).times(2).values('name') //初始節點1、一次循環和兩次循環結果都返回
==>marko
==>lop
==>vadas
==>josh
==>ripple
==>lop
emit()
和until()
可以加入限定,比如:
//從節點1開始按照向外的方向發現節點,直至葉子節點(沒有向外發出的邊)
gremlin> g.V(1).repeat(out()).until(outE().count().is(0)).path().by('name')
==>[marko,lop]
==>[marko,vadas]
==>[marko,josh,ripple]
==>[marko,josh,lop]
//從節點1開始按照向外的方向發現節點,所有路徑上出現的人名字都輸出
gremlin> g.V(1).repeat(out()).emit(hasLabel('person')).path().by('name')
==>[marko,vadas]
==>[marko,josh]
54 Sack Step
遍歷器可以包含稱為“麻袋(sack)”的本地數據結構。 sack()
步驟用於讀取和寫入sack(sideEffect或map)。每個遍歷器的每個袋子都會在使用以下語句時創建:
GraphTraversal.withSack(initialValueSupplier,splitOperator?,mergeOperator?).
- Initial value supplier: 供應商提供每個橫穿袋的初始值。
- Split operator: 一個一元操作符克隆(UnaryOperator),它會在遍歷器分裂時克隆所有的sack。
- Merge operator: 一個二進制運算符,它會在兩個遍歷器合並時,統一它們的sack。
Initial value supplier的例子:
gremlin> g.withSack(1.0f).V().sack()
==>1.0
==>1.0
==>1.0
==>1.0
==>1.0
==>1.0
gremlin> rand = new Random()
==>java.util.Random@4a52178
gremlin> g.withSack {rand.nextFloat()}.V().sack()
==>0.5063787
==>0.1647762
==>0.69914645
==>0.042134523
==>0.18742532
==>0.0388152
下面給出了一個更復雜的Initial value supplier示例,其中sack運行值用於運行計算,然后在遍歷結束時打印出來。當某條邊被遍歷后,邊緣權重會乘以sack值:
gremlin> g.withSack(1.0f).V(1).repeat(outE().sack(mult).by('weight').inV()).times(2).path().sack()
==>1.0
==>0.4
Note
mult來自於靜態引入的Operator.mult。
sack()
語法還有其他兩個可選參數Split operator 和Merge operator。
查看:http://tinkerpop.apache.org/docs/current/reference/#sack-step
55 Sample Step
sample()
步驟對於在遍歷之前的某些數量的遍歷器進行抽樣很有用。
gremlin> g.V().out('knows')
==>v[2]
==>v[4]
gremlin> g.V().out('knows').sample(1)
==>v[2]
gremlin> g.V().out('knows').sample(1)
==>v[4]
56 Select Step
Gremlin數據流處理圖形處理的一個區別在於流程不一定要“前進”,但實際上可以回到之前看到的計算區域。
一般有兩種方法來使用select()
步驟(map)。
- 在路徑中選擇標記的步驟(在遍歷中由
as()
定義)。 - 從
Map <String,Object>
流(即子地圖)中選擇對象。
- 使用
as()
在路徑中標記
gremlin> g.V().as('a').out().as('b').out().as('c').select('a','b','c')
==>[a:v[1],b:v[4],c:v[5]]
==>[a:v[1],b:v[4],c:v[3]]
- 使用map進行映射
gremlin> g.V().out('created').
project('a','b').
by('name').
by(__.in('created').count()).
select(`a`)
==>lop
==>lop
==>lop
==>ripple
- 使用
where()
進行過濾
例如,找出所有項目的共同開發者:
gremlin> g.V().as('a').out('created').in('created').as('b').select('a','b').by('name') //“共同開發者”包含自己
==>[a:marko,b:marko]
==>[a:marko,b:josh]
==>[a:marko,b:peter]
==>[a:josh,b:josh]
==>[a:josh,b:marko]
==>[a:josh,b:josh]
==>[a:josh,b:peter]
==>[a:peter,b:marko]
==>[a:peter,b:josh]
==>[a:peter,b:peter]
gremlin> g.V().as('a').out('created').in('created').as('b').select('a','b').by('name').where('a',neq('b')) //“共同開發者”排除自己
==>[a:marko,b:josh]
==>[a:marko,b:peter]
==>[a:josh,b:marko]
==>[a:josh,b:peter]
==>[a:peter,b:marko]
==>[a:peter,b:josh]
57 SimplePath Step
當遍歷時不想獲取循環的路徑,那么使用simplePath()
;當想獲取循環路徑,則使用cyclicPath()
。若不指定,則返回全部路徑。
gremlin> g.V(1).both().both().path() //所有路徑
==>[v[1],v[3],v[1]]
==>[v[1],v[3],v[4]]
==>[v[1],v[3],v[6]]
==>[v[1],v[2],v[1]]
==>[v[1],v[4],v[5]]
==>[v[1],v[4],v[3]]
==>[v[1],v[4],v[1]]
gremlin> g.V(1).both().both().simplePath().path() //非重復路徑
==>[v[1],v[3],v[4]]
==>[v[1],v[3],v[6]]
==>[v[1],v[4],v[5]]
==>[v[1],v[4],v[3]]
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]]
58 Skip Step
gremlin> g.V().values('age').order()
==>27
==>29
==>32
==>35
gremlin> g.V().values('age').order().skip(2)
==>32
==>35
gremlin> g.V().values('age').order().range(2, -1)
==>32
==>35
59 Store Step
gremlin> g.V().aggregate('x').limit(1).cap('x')
==>[v[1],v[2],v[3],v[4],v[5],v[6]]
gremlin> g.V().store('x').limit(1).cap('x')
==>[v[1],v[2]]
有趣的是,即使limit()
選擇是針對1個對象,store()
也有兩個結果。官網解釋為“Realize that when the second object is on its way to the range() filter (i.e. [0..1]), it passes through store() and thus, stored before filtered.”
60 Subgraph Step
subgraph()
步驟(sideEffect)提供了從遍歷生成邊導出子圖(Edge-Induced Subgraph)。
以下示例演示如何生成由邊“knows”導出的子圖:
gremlin> subGraph = g.E().hasLabel('knows').subgraph('subGraph').cap('subGraph').next() //1
==>tinkergraph[vertices:3 edges:2]
gremlin> sg = subGraph.traversal()
==>graphtraversalsource[tinkergraph[vertices:3 edges:2], standard]
gremlin> sg.E() //2
==>e[7][1-knows->2]
==>e[8][1-knows->4]
1:subgraph()
需要在邊步驟操作后調用;
2:子圖中只含有“knows”的邊。
更常見的子圖用例是獲取圍繞單個頂點的所有圖形結構.
例如,從頂點3開始,按照入射邊的方向逆行1次,將結果全部輸出到子圖中:
gremlin> subGraph = g.V(3).repeat(__.inE().subgraph('subGraph').outV()).times(1).cap('subGraph').next()
==>tinkergraph[vertices:4 edges:3]
gremlin> sg = subGraph.traversal()
==>graphtraversalsource[tinkergraph[vertices:4 edges:3], standard]
gremlin> sg.E()
==>e[9][1-created->3]
==>e[11][4-created->3]
==>e[12][6-created->3]
可以考慮上述例子中,逆行2步的結果:
gremlin> subGraph = g.V(3).repeat(__.inE().subgraph('subGraph').outV()).times(2).cap('subGraph').next()
==>tinkergraph[vertices:4 edges:4]
gremlin> sg = subGraph.traversal()
==>graphtraversalsource[tinkergraph[vertices:4 edges:4], standard]
gremlin> sg.E()
==>e[8][1-knows->4]
==>e[9][1-created->3]
==>e[11][4-created->3]
==>e[12][6-created->3]
接着考慮,逆行3步的結果,在Modern
圖的情形中,結果是否與逆行2步一樣?其實結果是一樣的。
61 Sum Step
sum()
步驟(map)示例:
gremlin> g.V().values('age')
==>29
==>27
==>32
==>35
gremlin> g.V().values('age').sum()
==>123
62 Tail Step
tail()
步驟,用於從尾部開始獲取元素。示例如下:
gremlin> g.V().values('age').order()
==>27
==>29
==>32
==>35
gremlin> g.V().values('age').order().tail()
==>35
gremlin> g.V().values('age').order().tail(2)
==>32
==>35
tail()
步驟支持Scope.local
參數,如下:
gremlin> g.V().valueMap()
==>[name:[marko],age:[29]]
==>[name:[vadas],age:[27]]
==>[name:[lop],lang:[java]]
==>[name:[josh],age:[32]]
==>[name:[ripple],lang:[java]]
==>[name:[peter],age:[35]]
gremlin> g.V().valueMap().tail(local,1)
==>[age:[29]]
==>[age:[27]]
==>[lang:[java]]
==>[age:[32]]
==>[lang:[java]]
==>[age:[35]]
63 TimeLimit Step
可能希望遍歷執行不超過2毫秒。在這種情況下,可以使用timeLimit()
步驟(filter)。
64 To Step
to()
- 步驟不是一個實際的步驟,而是一個類似於as()
和by()
的“步驟調制器”。如果一個步驟能夠接受遍歷或字符串,那么to()
是添加它們的手段。
支持to()
的步驟包括:
simplePath()
cyclicPath()
path()
addE()
示例:
gremlin> g.addV().property(id, "101").as("a").
addV().property(id, "102").as("b").
addV().property(id, "103").as("c").
addV().property(id, "104").as("d").
addE("link").from("a").to("b").
addE("link").from("b").to("c").
addE("link").from("c").to("d").iterate()
gremlin> g.V('101').repeat(both().simplePath()).times(3).path()
==>[v[101],v[102],v[103],v[104]]
65 Tree Step
從任何一個元素(即頂點或邊),可以聚合來自該元素的發出路徑以形成樹。 Gremlin為這種情況提供了tree()
步驟(sideEffect)。
gremlin> tree = g.V().out().out().tree().next()
==>v[1]={v[4]={v[3]={}, v[5]={}}}
- 獲取樹后進行深度遍歷
gremlin> tree = g.V().out().out().tree().next()
==>v[1]={v[4]={v[3]={}, v[5]={}}}
gremlin> tree.getObjectsAtDepth(3)
==>v[3]
==>v[5]
66 Unfold Step
如果達到unfold()
(flatMap)的對象是一個迭代器,可迭代或映射,那么它將被展開成一個線性形式。
gremlin> g.V(1).out().fold()
==>[v[3],v[2],v[4]]
gremlin> g.V(1).out().fold().unfold()
==>v[3]
==>v[2]
==>v[4]
67 Union Step
union()
步驟(branch)支持合並任意數量的遍歷的結果。當遍歷器達到union()
步驟時,它被復制到其每個內部步驟。
gremlin> g.V(4).union(
__.in().values('age'),
out().values('lang'))
==>29
==>java
==>java
gremlin> g.V(4).union(
__.in().values('age'),
out().values('lang')).path()
==>[v[4],v[1],29]
==>[v[4],v[5],java]
==>[v[4],v[3],java]
68 Value Step
value()
步驟(map)取一個Property並從中提取該值。
gremlin> g.V(1).properties().value()
69 ValueMap Step
valueMap()
步驟生成元素屬性的Map表示。
gremlin> g.V().valueMap()
==>[name:[marko],age:[29]]
==>[name:[vadas],age:[27]]
==>[name:[lop],lang:[java]]
==>[name:[josh],age:[32]]
==>[name:[ripple],lang:[java]]
==>[name:[peter],age:[35]]
重要的是注意,頂點的地圖維護每個鍵的值列表。邊或頂點屬性的映射表示單個屬性(不是列表)。原因是TinkerPop3中的頂點會利用每個鍵支持多個值的頂點屬性(VertexProperty)。
如果需要該元素的id,label,key和value,則boolean會將其插入到返回的映射中:
gremlin> g.V().hasLabel('person').valueMap(true)
==>[name:[marko],id:1,location:[san diego,santa cruz,brussels,santa fe],label:person]
==>[name:[stephen],id:7,location:[centreville,dulles,purcellville],label:person]
==>[name:[matthias],id:8,location:[bremen,baltimore,oakland,seattle],label:person]
==>[name:[daniel],id:9,location:[spremberg,kaiserslautern,aachen],label:person]
來源: http://tinkerpop.apache.org/docs/current/reference/#union-step
70 Values Step
values()
步驟(map)從遍歷流中的元素中提取屬性的值。
gremlin> g.V(1).values()
==>marko
==>san diego
==>santa cruz
==>brussels
==>santa fe
gremlin> g.V(1).values('location')
==>san diego
==>santa cruz
==>brussels
==>santa fe
71 Vertex Steps
頂點步驟(flatMap)是Gremlin語言的基礎。通過這些步驟,它可能在圖形上“移動” - 即遍歷。
out(string…)
:移動到給定邊標簽的出站的相鄰頂點。
in(string…)
:移動到給定邊標簽的傳入的相鄰頂點。
both(string…)
:移動到給定邊標簽的傳入和傳出的相鄰頂點。
outE(string…)
:移動到給定邊標簽的出站事件邊。
inE(string…)
:移動到給定邊標簽的入站事件邊。
bothE(string…)
:移動到給定邊標簽的入站和出站事件邊。
outV()
:移動到傳出的頂點。
inV()
:移動到傳入的頂點。
bothV()
:移動到兩個頂點。
otherV()
:移動到不是從中移出的頂點的頂點。
Note
out/in/both等獨立單詞的頂點步驟,由定點調用;
outE/inE等涉及邊的頂點步驟,由定點調用;
outV/inV/bothV/otherV等步驟,由邊調用;
72 Where Step
where()
步驟(filter)根據對象本身(Scope.local)或對象(Scope.global)的路徑歷史來過濾當前對象。該步驟通常與match()
或select()
結合使用,但可以獨立使用。
如獲取節點1的合作者,去除節點1本身:
gremlin> g.V(1).as('a').out('created').in('created').where(neq('a'))\
==>v[4]
==>v[6]
幾個典型的例子:
gremlin> g.V().where(out('created')).values('name') //1\
==>marko
==>josh
==>peter
gremlin> g.V().out('knows').where(out('created')).values('name') //2\
==>josh
gremlin> g.V().where(out('created').count().is(gte(2))).values('name') //3\
==>josh
gremlin> g.V().where(out('knows').where(out('created'))).values('name') //4\
==>marko
gremlin> g.V().where(__.not(out('created'))).where(__.in('knows')).values('name') //5\
==>vadas
gremlin> g.V().where(__.not(out('created')).and().in('knows')).values('name') //6\
==>vadas
gremlin> g.V().as('a').out('knows').as('b').
where('a',gt('b')).
by('age').
select('a','b').
by('name') //7\
==>[a:marko,b:vadas]
gremlin> g.V().as('a').out('knows').as('b').
where('a',gt('b').or(eq('b'))).
by('age').
by('age').
by(__.in('knows').values('age')).
select('a','b').
by('name') //8\
==>[a:marko,b:vadas]
==>[a:marko,b:josh]
1、創建項目的人的名字是什么?
2、被人熟知,且創建了一個項目的人的名字是什么?
3、創造了兩個或多個項目的人的名字是什么?
4、那些知道有人創造了一個項目的人的名字是什么?
5、沒有創造任何東西但被某人知道的人的名字是什么?
6、where()
步驟的連接與一個單一的where()
加and子句的相果相同。
7、marko知道josh和vadas,但是比vadas老了。
8、marko比josh小,但是知道josh的人與marko年齡相等(就是marko)。