ArangoDB 学习笔记 (4)graph

一个graph包含vertices 和edges。edges被存储在edges document当中。vertices可以是document collection 中的document也可以是edge document中的document。所以说edges也可以被当做vertices来使用。

1、数据准备

使用arangoimp导入飞机场和航班csv数据信息。

导入飞机场信息

arangoimp --file path to airports.csv 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 path to flights.csv 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
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,只用一次遍历即可完成。因此联合索引大大提高了遍历的效率。

 

posted @ 2018-09-15 15:52  tutu_python  阅读(2253)  评论(0编辑  收藏  举报