ArrangoDB文档/By aakz0347

六、图

(一)图基础

1.种类:无向图,有向图,有向无环图(如下图所示)

01

在 ArangoDB 中,采用的是有向无环图(Directed Acyclic Graph):每条边只有一个方向,不能同时指向两个方向。边始终是有方向的,但是当遍历(traversal)时可能沿着箭头反方向,此时可以不管方向问题

2.ArangoDB 允许您存储各种不同形状和大小的图形,有循环和无循环。您可以保存两个顶点之间甚至同一个顶点之间的一条或多条边。另请注意,边是完整的 JSON 文档,可以根据需要在边上存储尽可能多的信息。

3.节点Document Collection:每条信息都是一个JSON对象,且内置主索引;每条信息都有一个唯一的_key

Edge Collection:边属性是存放关系的地方,也包含信息,其中必包含_from_to,分别表示源顶点和目标顶点的_id

4.图的应用场景:每当搜索深度未知(要遵循多少条边)时,与其他查询模式相比,图形查询更容易编写且计算效率更高。

360° 视图(市场数据、客户、用户……) 人工智能 依赖管理 欺诈识别 身份和访问管理 知识图谱 主数据管理

网络基础设施 推荐引擎 风险管理 社交媒体管理

(二)用ArrangoDB的AQL进行图遍历

从集合中查找一条信息:Document()函数

这是通过 _id 获取John F. Kennedy机场的信息,使用主索引来查询文档。

_key 过滤:

FOR airport IN airports   
  FILTER airport._key == "JFK"   
  RETURN airport

筛选且仅返回机场名称:

FOR a IN airports   
  FILTER a._key IN ["JFK", "LAX"]
  RETURN { fullName: a.name }
(三)遍历相关

1.遍历深度

2.语法:vertex顶点 outbound离开,向外,表示遍历方向和图的箭头方向相同;inbound进入,向内,表示遍历方向和图的箭头方向相反。

FOR vertex[, edge[, path]]
  IN [min[..max]]
  OUTBOUND|INBOUND|ANY startVertex
  edgeCollection[, more…]

3.实例

/*返回相邻机场的名称:它可以从洛杉矶国际机场 (LAX) ,沿flights边1步到达到达*/
WITH airports
FOR airport IN 1..1 
  OUTBOUND
  'airports/LAX' flights
  RETURN DISTINCT airport.name

WITH
An AQL query can start with a WITH keyword followed by a list of collections from which the query implicitly reads. This is required when doing graph traversals in a clustered environment. By implicit, we mean that the collections are not specified explicitly in language constructs like in the previous example.

WITH airports
FOR airport IN 1..1
OUTBOUND
‘airports/LAX’ flights

Here we do explicitly declare the flights collection, but we don’t actually declare the airports in our FOR declaration, and that is why it is included as a part of the WITH statement. Doing this ensures that the query optimizer can maintain performance at runtime in a clustered environment.

Collections that are explicitly used in a query are automatically detected by the AQL query parser. Any additional collections that will be involved in the query but cannot be detected automatically by the query parser can be manually specified using a WITH statement.

WITH + FOR是固定搭配,WITH隐式指出了集合,使得不用在FOR中声明机场airport

/*返回任意 10 个航班文件:它们包含从LAX起飞的航班信息、目的地机场名。应该形如如下形式:*/
'''
  {
    "airport": {
      "_key": "CVG",
      "_id": "airports/CVG",
      ...
      "vip": false
    },
    "flight": {
      "_key": "306520699",
      "_id": "flights/306520699",
      "_from": "airports/LAX",
      "_to": "airports/CVG",
      ...
      "FlightNum": 704,
    }
  }
'''

/*answer*/
WITH airports
FOR airport, flight IN 
  OUTBOUND 
  'airports/LAX' flights
  LIMIT 10
  RETURN {airport, flight}
/*返回 10 个航班号,飞机降落在 Bismarck Municipal Airport (BIS)。*/   /*  airports/BIS  */
WITH airports               要使用的集合
FOR airport, flight IN 
INBOUND                     要遍历的方向:向airports/BIS
'airports/BIS' flights      要遍历的边:flights是边集合的名称
    LIMIT 10
RETURN flight.FlightNum

'airports/BIS'是一个文档句柄,它指定了要查询的文档。在AQL中,文档句柄由集合名称和文档键组成,用/分隔。在这个例子中,airports是集合名称,而BIS是文档键。

WITH airports FOR vertex, edge, path IN OUTBOUND 'airports/LAX' flights LIMIT 10 RETURN edge

WITH airports FOR airport, flight IN OUTBOUND 'airports/LAX' flights LIMIT 10 RETURN flight

上面两个语句等价:

这两个语句都是查询与'airports/LAX'文档相关联的前10条边。第一个语句使用了vertex, edge, path变量来访问遍历过程中的顶点、边和路径,而第二个语句只使用了airport, flight变量来访问顶点和边。

在这两个语句中,我们都只关心边,因此我们可以使用任何一个变量来返回边。在第一个语句中,我们使用RETURN edge来返回边,而在第二个语句中,我们使用RETURN flight来返回边。由于这两个变量都指向相同的边,因此这两个语句是等价的。

(四)遍历进阶
遍历方法:BFS/DFS

对于最小深度≥2的遍历,一般有两种方法:

  • 深度优先(默认):继续沿着该路径上的起始顶点到最后一个顶点的边或直到达到最大遍历深度,然后沿着其他路径走。
  • 广度优先(可选):跟随从起始顶点到下一层的所有边,然后跟随它们邻居的所有边到另一层并继续这种模式,直到没有更多的边可以跟随或达到最大遍历深度。
  FOR v IN 1..10 OUTBOUND 'verts/S' edges       /*1..10表示遍历深度为10层*/
     OPTIONS {bfs: true}
     FILTER v._key == 'F'
     LIMIT 1
     RETURN v
 /*把查询限制为单个匹配*/

这是一个有效的AQL查询,它将沿着edges集合中指向'verts/S'文档的边进行遍历,最多遍历10层。遍历使用了广度优先搜索(BFS)算法,并且只返回键为'F'的顶点。由于使用了LIMIT 1,因此查询最多返回一个结果。

唯一性

唯一性:并非每个图都只有一条从所选起始顶点到其连接顶点的路径。图中甚至可能存在循环。

默认情况下,如果再次遇到已经访问过的边,则沿任何路径的遍历都会停止。它可以防止遍历绕圈子运行。

如上图所示,为了避免S-B-C-S这一结果重复进行,可以如下操作:

FOR v, e, p IN 1..5 OUTBOUND 'verts/S' 边
  OPTIONS { 
    uniqueVertices: 'none', 
    uniqueEdges: 'path' 
  } RETURN CONCAT_SEPARATOR ('->', p.vertices[*]._key)

uniqueEdges:'none' 将使遍历器遵循从 S 到B到C再到S,再从S到B再到C。它只会停在那里,因为此时已达到最大深度 5。如果查询的最大深度更高,则遍历将运行很长时间,由于循环会产生大量路径。

uniqueVertices: 'path' 确保每个单独的路径上没有重复的顶点。

uniqueVertices: 'global' 确保在整个遍历过程中访问每个可到达的顶点一次。

它需要 bfs: true(广度优先搜索)。深度优先搜索dfs不支持它,因为结果将是完全不确定的(在查询运行之间变化),因为遍历器遵循顶点边缘的顺序没有规则。只要有多条路径可供选择,唯一性规则将导致随机排除路径,它会从中选择一条。

WITH airports
FOR airport IN OUTBOUND 'airports/LAX' flights
  OPTIONS { bfs: true, uniqueVertices: 'global' }
  RETURN airport
WITH airports
FOR airport IN OUTBOUND 'airports/LAX' flights
  RETURN DISTINCT airport

这两段代码是等价的:它们都将返回与'airports/LAX'文档相关联的所有唯一顶点。

第一个查询使用了OPTIONS { bfs: true, uniqueVertices: 'global' }来指定遍历算法和确保每个顶点只被访问一次。第二个查询使用了RETURN DISTINCT airport来去除重复的顶点。但在数据集较大时使用uniqueVertices的性能明显更高。

最短路径问题

SHORTEST_PATH是一个AQL函数,它用于计算两个顶点之间的最短路径。您可以使用这个函数来查询图数据,并返回两个顶点之间的最短路径。

Find a shortest path between Bismarck Municipal Airport and John F. Kennedy airport and return the airport names on the route

WITH airports
FOR v IN OUTBOUND
  SHORTEST_PATH 'airports/BIS'
  TO 'airports/JFK' flights
  RETURN v.name

返回从 BIS 到 JFK 的最少航班:使用LET

WITH airports
LET airports = (
  FOR v IN OUTBOUND
    SHORTEST_PATH 'airports/BIS'
    TO 'airports/JFK' flights
    RETURN v
)
RETURN LENGTH(airports) - 1
模式匹配识别

用于在考虑整个路径的遍历中应用复杂的过滤条件

FOR endVertex, edgeToVertex INFOR vertex, edge, path IN