TinkerPop中的遍歷:圖的遍歷步驟(3/3)


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>流(即子地圖)中選擇對象。
  1. 使用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]]
  1. 使用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)。
tree step2

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() 步驟時,它被復制到其每個內部步驟。
union step

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語言的基礎。通過這些步驟,它可能在圖形上“移動” - 即遍歷。
vertex steps

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM