我在ArangoDB中有一个简单的节点链接图。如何从1个预选节点遍历并返回与其相关的所有节点?
例如: A→B,B→C,C→D,C→E,F→B,F→E
选择其中任何一个都应返回相同的结果(全部)。
我是ArangoDB的新手。
答案 0 :(得分:12)
您需要的是AQL graph traversal,自ArangoDB 2.8以来可用。较旧的版本提供了一组与图形相关的函数,但本机AQL遍历更快,更灵活,从3.0开始,图形函数不再可用。
AQL遍历让你跟随连接到起始顶点的边,直到可变深度。可以访问每个遇到的顶点,例如,用于过滤或构造结果,以及引导您到达此顶点的边缘以及从开始到结束的完整路径,包括顶点和边缘。
在您的情况下,只需要返回被访问顶点的名称。您可以运行以下AQL查询,假设有一个文档集合node
和一个边集合links
,它们包含此图表的数据:
// 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 DISTINCT
,COLLECT
或类似的东西来删除重复项。但我们最好调整遍历选项,不要不必要地跟随边缘。
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操作。希望这有助于=)