ArangoDB:获取与所选节点有任何关联的每个节点

时间:2016-08-03 12:47:00

标签: arangodb graph-traversal

我在ArangoDB中有一个简单的节点链接图。如何从1个预选节点遍历并返回与其相关的所有节点?

例如: A→B,B→C,C→D,C→E,F→B,F→E

选择其中任何一个都应返回相同的结果(全部)。

我是ArangoDB的新手。

1 个答案:

答案 0 :(得分:12)

您需要的是AQL graph traversal,自ArangoDB 2.8以来可用。较旧的版本提供了一组与图形相关的函数,但本机AQL遍历更快,更灵活,从3.0开始,图形函数不再可用。

AQL遍历让你跟随连接到起始顶点的边,直到可变深度。可以访问每个遇到的顶点,例如,用于过滤或构造结果,以及引导您到达此顶点的边缘以及从开始到结束的完整路径,包括顶点和边缘。

在您的情况下,只需要返回被访问顶点的名称。您可以运行以下AQL查询,假设有一个文档集合node和一个边集合links,它们包含此图表的数据:

Example Graph

// follow edges ("links" collection) in outbound direction, starting at A
FOR v IN OUTBOUND "node/A" links
    // return the key (node name) for every vertex we see
    RETURN v._key

这只会返回[ "B" ],因为遍历深度隐含1..1(min = 1,max = 1)。如果我们增加最大深度,那么我们可以包括间接连接的节点:

FOR v IN 1..10 OUTBOUND "node/A" links
    RETURN v._key

这会给我们[ "B", "C", "D", "E"]。如果我们查看图形,这是正确的:我们只跟随从我们来自顶点的边到另一个顶点(箭头的方向)。反过来说,我们可以使用INBOUND,但在你的情况下,我们想要忽略边缘的方向并遵循:

FOR v IN 1..10 ANY "node/A" links
    RETURN v._key

首先结果可能有点令人惊讶:
[ "B", "C", "D", "E", "F", "B", "F", "E", "C", "D", "B" ]

我们看到返回了重复的节点。原因是例如从A到C有多条路径(通过B和B-F-E),查询将每条路径的最后一个节点作为变量v返回。 (它实际上并不处理所有可能的路径,最大深度为10,但您可以设置遍历选项OPTIONS {uniqueEdges: "none"}来执行此操作。)

它可以帮助返回格式化的遍历路径,以更好地了解正在发生的事情(即如何到达节点):

FOR v, e, p IN 1..10 ANY "node/A" links OPTIONS {uniqueEdges: "path"}
    RETURN CONCAT_SEPARATOR(" - ", p.vertices[*]._key)

结果:

[
  "A - B",
  "A - B - C",
  "A - B - C - D",
  "A - B - C - E",
  "A - B - C - E - F",
  "A - B - C - E - F - B",
  "A - B - F",
  "A - B - F - E",
  "A - B - F - E - C",
  "A - B - F - E - C - D",
  "A - B - F - E - C - B"
]

图中有一个循环,但不能有无限循环,因为10跳后超过了最大深度。但正如你在上面看到的那样,它甚至没有达到10的深度,而是停止,因为(默认)选项是不跟踪每个路径两次的边(uniqueEdges: "path")。

无论如何,这不是理想的结果。一个便宜的技巧是使用RETURN DISTINCTCOLLECT或类似的东西来删除重复项。但我们最好调整遍历选项,不要不必要地跟随边缘。

uniqueEdges: "global"仍会包含B节点两次,但uniqueVertices: "global"会提供所需的结果。此外,在这种情况下,可以使用bfs: true进行广度优先搜索。不同之处在于到F节点的路径较短(A-B-F而不是A-B-C-E-F)。一般而言,您应该使用的确切选项在很大程度上取决于数据集和您的问题。

还有一个问题需要解决:遍历不包括起始顶点(除了每个路径的p.vertices[0]之外)。使用ArangoDB 3.0或更高版本可以通过将最小深度设置为0来轻松解决这个问题:

FOR v IN 0..10 ANY "node/A" links OPTIONS {uniqueVertices: "global"}
    RETURN v._key

[ "A", "B", "C", "D", "E", "F" ]

要验证是否返回了从A到F的所有节点,无论起始顶点如何,我们都可以发出以下测试查询:

FOR doc IN node
    RETURN (
        FOR v IN 0..10 ANY doc links OPTIONS {uniqueVertices: "global"}
            SORT v._key
            RETURN v._key
    )

所有子阵列看起来都一样。如果要以遍历顺序返回节点名称,请删除SORT操作。希望这有助于=)