缩放ArangoDb中的图形遍历

时间:2016-02-03 15:25:18

标签: graph graph-databases arangodb

我有一个树状结构,实际上是一个有向无环图。一个小版本如下所示。 minimal graph

在任何父级,我想总结子树的一些属性。今天我在AQL中使用TRAVERSAL和COLLECT基于起始节点执行此操作:

var str = "test %s, test %%, test %%s too";
var output = str.replace(/%%|%s|./g, function(match, capture) { 
  return match.replace("%%", "%").replace("%s", "foobar");
});
console.log("output:", output);

然后我可以在组上使用聚合。 (使用ArangoDB 2.8,我相信现在可以直接在collect语句中完成。)唯一性选项解决了重复问题。

缩放

当树(图)增长到相当大的尺寸(10-20k节点)时,这将如何扩展?我需要快速,因为用户将等待响应(不是长时间运行的作业)。

我想在节点中缓存值并且有一个标志。然后在节点1中可以只加2和3,如果它们都是 clean 问题是5和2和3的总和。

我该如何解决这个问题?或者这是一个非问题 - 遍历真的那么快吗?

到目前为止,我已经提出让每个节点都包含它的子树副本列表的想法,在1的情况下,这意味着信息" 5是包括两次"。这可以用来从1的总数中减去这个。但我怎么能找到这些信息呢?我已经考虑过使用> 1父节点查找所有节点,然后向上遍历(快速),然后以某种方式计算此信息。

1 个答案:

答案 0 :(得分:2)

遍历的运行时间受到进程中实际触及的顶点和边缘数量的限制。因此,遍历的运行时间取决于路径的深度和分支因子(预期有多个具有多个父项的顶点)。

您描述的构造问题是遍历将选择从15的一条路径(比如左边的路径)并对所有值求和并最终返回1选择正确的道路。现在它再次达到5,但这次搜索深度低于上次5的搜索深度,因此它必须再次实际遍历5上的子树,因为它现在可能会获得更大的距离在这条路径中(它不知道这个子树上的所有顶点都可以在更短的距离内到达)。此路径上的顶点不会再次调用访问者,但仍会遍历并跟踪,这会花费时间。

我尝试优化遍历来验证扩展。 首先,我注册了一个新的优化访问者:

require("@arangodb/aql/functions").register("test::counter", "function (config, result, vertex) {result[0] = result[0] || {value: 0}; result[0].value += vertex.value}");

此访问者对顶点的值进行求和并直接返回它们,因此我可以删除COLLECT语句。我可以使用它我的AQL:

FOR x IN TRAVERSAL(TestVertices, TestEdges, 'TestVertices/0', 'outbound', {uniqueness:{vertices:'global'}, visitor: 'test::counter', maxDepth: 5012})
  RETURN x.value

请注意:我在选项中提供了maxDepth以进行高深度搜索,默认为256

我的测试树基本上是一个20.000个顶点的链,其中每个第三个顶点都有一个额外的边到链后面的随机顶点(模拟你描述的多个父节点问题)

通过此遍历,我设法从5012中的根搜索~5 secs的深度。使用更高的深度,它呈指数增长。

我假设您的图表中有多个父项,所以我希望图表上的运行时间更少。

如果您期望更多读取然后写入,您还可以考虑计算每次写入的总和。 这将减慢写入速度,但会立即进行所有读取。

作为示例,您可以在更新值时使用以下AQL:

LET i = (FOR x IN 1..5012 INBOUND @start TestEdges
           RETURN DISTINCT x) 
  FOR x IN i UPDATE x WITH {sum: x.sum + @add} IN TestVertices

使用绑定参数@add表示要添加的值,使用@start表示更新的顶点。使用这种技术,您的阅读查询是微不足道的:

FOR x IN TestVertices FILTER x._id == @start 
  RETURN x.sum

希望这有帮助。

相关问题