一個graph包含vertices 和edges。edges被存儲在edges document當中。vertices可以是document collection 中的document也可以是edge document中的document。所以說edges也可以被當做vertices來使用。
1、數據准備
使用arangoimp導入飛機場和航班csv數據信息。
導入飛機場信息
arangoimp --file <em>path to airports.csv</em> on your machine --collection airports --create-collection true --type csv
這里我們創建了一個document collection;為每一行創建一個document.標題被作為屬性名稱。其中標題中包含一個_key的值,系統將自動識別該列作為_key.
現在打開瀏覽器(http://localhost:8529)便可以看到剛剛導入的信息了。
可以點擊瀏覽器中的queries進行查詢:
查詢所有的機場
FOR airport in ariports RETURN airport
僅查詢加利福尼亞機場信息
FOR airport IN airports FILTER airport.state==‘CA’ RETURN airport
查詢每個州擁有的機場數量
FOR airport IN airports COLLECT state = airport.state WITH COUNT ON counter RETURN {state,counter}
導入航班信息
arangoimp --file <em>path to flights.csv</em> on your machine --collection flights --create-collection true --type csv --create-collection-type edge
這里創建的是edge collection,為每一行創建一個edge,同時自動創建一個edge index方便快速查詢(_from和_to組成了這樣的index.).在csv中有兩個特殊的列_from 和_to,它們的值為airports collection中的id,指明了從一個機場飛往另外一個機場。
2、graph數據查詢
語法
FOR Vertex,Edge,Path IN [min..max ] [OUTBAND|INBOUND|ANY] startvertex EDGECOLLECTION
分析:
FOR 遍歷三個變量,分別是點(vertex)、關聯(edge),點和關系組成的路線(path)
IN 在哪個EDGE COLLECTION中
[min..max]遍歷的最小深度、最大深度或者遍歷的深度范圍
OUTBOUND:從startvertex原始斷點開始向外查詢,即from 為startvertex;INBOUND為向內查詢,即to為startvertex,any:兩個方向全部查詢
startvertex:開始查詢的斷點
EDGE COLLECTION 遍歷的collection,可以是一個或多個edge collection
查詢示例:
查所洛杉磯可以直達的所有飛機場
FOR airport IN OUTBOUND 'airports/LAX' flights RETURN DISTICT airport
返回10個從洛杉磯可以到達的飛機場及其航班。
FOR ariport flight IN OUTBOUND 'airports/LAX' LIMIT 10 flights RETURN {airpot,flight}
3、查詢選項
(1)遍歷深度優先還是廣度優先
所有遍歷查詢默認是深度優先,深度優先和廣度優先都會返回相同的結果。但計算性能有時會相差很大。
如果要得到所有的節點,那么深度優先和廣度優先效率一樣。因為都要跑完所有的節點。
如果要是有篩選filter或者限制(limit)導致不完全篩選,那廣度優先可能會有更高的效率。
廣度優先示例:
FOR v IN 1..10 OUTBOUND 'vertical/s' edgs<br>OPTIONS {bfs:true} FILTER v._key=='F' LIMIT 1 RETURN v
(2)唯一遍歷
由於不同點之間的路徑可能有多條,也可能存在閉環線路
默認情況下,遍歷的時候如果path中遇到了相同的edge就會停止遍歷;這將可以防止遍歷存在繞圈情況,讓遍歷可以到達最底層節點。
在一個path上可能會出現重復的vertex,除非你明確聲明不要重復的點。
示例
FOR v,e,p IN 1..5 OUTBOUND 'vertex/s' edgs OPTIONS { uniqueVertices:'none', uniqueEdges:'path' } RETURN CONCAT_SEPARATOR('->',p.vertices[*]._key)
這個uniqueVertices:‘none’和uniqueEdges:‘path’都是默認設置,不設置也是一樣。這樣最開是的節點也可以是最后的節點,因為我們在設置的時候並沒有要求path中有唯一的點。如果要設置為唯一的,可以也設置為‘path’,這樣一條路徑中的點也將變為唯一的。
global保證每個點在所有遍歷中只出現一次。它僅適用於廣度優先。示例
FOR v IN 1..5 OUTBOUND 'vertex/s' edgs OPTIONS{ bfs:ture, uniqueVertices:'global' RETURN v._key
從洛杉磯可以直達的機場
FOR ariport IN OUTBOUND 'airports/LAX' flights OPTIONS { bfs:true, uniqueVertices:'global'} RETURN airport
這個查詢將比上面的使用distict快很多。因為distict是在遍歷完所有節點后再去除重復的,而options則可以直接過掉重復的結果不進行遍歷。
4、LET關鍵字
LET可以用來聲明變量,來將查詢結果賦值給變量。
FOR f IN flights FILTER f._from == 'airports/BIS' LIMIT 100 LET h = FLOOR(f.DepTime / 100) LET m = f.DepTime % 100 RETURN { year: f.Year, month: f.Month, day: f.DayofMonth, time: f.DepTime, iso: DATE_ISO8601(f.Year, f.Month, f.DayofMonth, h, m) }
5、shortest_path最短路徑
找到BIS 和JFK之間的最短路徑
FOR v IN OUTBOUND SHORTEST_PATH 'airports/BIS' TO 'airports/JFK' flights RETURN v
注意,最短路徑只是找到一條路徑進行返回,其實可能還有其他的可能性。
LET airports = ( FOR v IN OUTBOUND SHORTEST_PATH 'airports/BIS' TO 'airports/JFK' flights RETURN v ) RETURN LENGTH(airports) - 1
找到最少需要經過的機場,-1代表不包括最后一個節點。
在SHORTEST_PATH中不能使用filter只能使用pattern matching代替。
6、pattern matching
問題:找到BIS 和 JFK之間最短的旅行時間。
第一步:找到BIS和JFK之間的最短路徑,我們已經知道最短路徑為2.
FOR v,e,p IN 2 OUTBOUND 'airports/BIS' flights FILTER v.id='airports/JFK' LIMIT 5 RETURN p
第二步:我們確定在同一天內,假設都為1月1日。
FOR v,e,p IN 2 OUTBOUND 'airports/BIS' flights FILTER v._id='airports/JFK' FILTER p.edges[*].month all == 1 FILTER p.edges[*].DayOfMonth all == 1 LIMIT 5 RETURN p
數組之間的比較可以使用all,any ,none來表示。
第三步:計算每條path的飛行時間,並按照升序排列,這里使用DATE.DIFF()來計算
FOR v,e,p IN 2 OUTBOUND 'airports/BIS' flights FILTER v._id='airports/JFK' FILTER p.edges[*].month.all == 1 FILTER p.edges[*].DayofMonth all == 1 LET flightTime = DATE_DIFF(p.edges[0].DepTimeUTC-p.edges[1].ArrTimeUTC,'i') SORT filghtTIme ASC LIMIT 5 RETURN {flight:p,time:flightTime}
第四步:確定讓中轉時候的到達時間小於離開時間20分鍾
FOR v, e, p IN 2 OUTBOUND 'airports/BIS' flights FILTER v._id == 'airports/JFK' FILTER p.edges[*].Month ALL == 1 FILTER p.edges[*].DayofMonth ALL == 1 FILTER DATE_ADD(p.edges[0].ArrTimeUTC, 20, 'minutes') < p.edges[1].DepTimeUTC LET flightTime = DATE_DIFF(p.edges[0].DepTimeUTC, p.edges[1].ArrTimeUTC, 'i') SORT flightTime ASC LIMIT 5 RETURN { flight: p, time: flightTime }
使用index進行優化
建立一個點中心索引,以_from,Month,DayOfMonth三個為聯合索引字段。即將FILTER的三個字段作為索引字段。
如果不以三個為聯合索引,那么系統將自動從首先篩選_from,其次遍歷month,其次遍歷_day,有了聯合索引直接就會找到‘airports/jfk’,month=1,dayofmonth=1,只用一次遍歷即可完成。因此聯合索引大大提高了遍歷的效率。
本文章轉載於博客園-ArangoDB 學習筆記 (4)graph