CouchDB定向非循环图(DAG)

时间:2010-09-18 01:12:59

标签: javascript couchdb mapreduce

如果我的结构如下:

[{Name: 'A', Depends: []},
{Name: 'B', Depends: ['A']},
{Name: 'C', Depends: ['A']},
{Name: 'D', Depends: ['C']},
{Name: 'E', Depends: ['D','B']}]

我如何编写地图并减少功能,使我的输出为:

[{Key: 'A', Value: []},
{Key: 'B', Value: ['A']},
{Key: 'C', Value: ['A']},
{Key: 'D', Value: ['A','C']}
{Key: 'E', Value: ['D','B','C','A']}]

我得到map函数需要抛出它的依赖项,但是我不知道reduce会如何保留它们以便它们可以在树中进一步应用而不会将性能抛到窗外并等待所有映射申请。我也不能使用路径,因为并不总是有一条独特的路径(例如,D A-> C-> D或A-> D)。

2 个答案:

答案 0 :(得分:0)

如果它真的是关于javascript,那么我想你没有太多选择。

您可能希望编写自己的实现:http://www.electricmonk.nl/log/2008/08/07/dependency-resolving-algorithm/

对于存储集(仅包含唯一值的数组),我建议使用关联数组并使用其键。

Array.map()函数也可能有用。

答案 1 :(得分:0)

您需要第二个或辅助的couchdb数据库,我们称之为“complete_dependencies”。其文档将是每个节点的计算完整依赖项。其文件的格式为

{姓名:'D',CompleteDepends:['C','A']}

此db也会有一个视图'implies'显示每个元素依赖于他的所有元素。对于前一个元素,它将发出:

[{Name:'C',Implies:'D'},{Name:'A',Implies:'D'}]

您将使用Change Notifications API来实现此db。它将处理在原始数据库中修改的每个文档并计算其完整的依赖项。请注意,此处理不是视图。是一个程序使它成为您选择的语言,听取修改api和处理每个文档。对于每个文档,它将执行以下操作:

1)使用我们的complete_dependencies db。

计算其完整的依赖关系

2)查看视图'隐含'哪些文档依赖于修改后的文档并重新计算它们。这是一件需要注意的事情。要使用complete_dependencies,必须正确计算它们,因此在使用文档的complete_dependencies条目之前,您必须确保文档不在“隐含”列表中或已经计算过。

重要的一点是,这些函数都不是递归的。

它将遵循:

第一个文件是{姓名:'A',取决于:[]}。因为没有依赖关系(1)它不会做任何事情,因为隐含视图是空的(2)也将什么都不做。

第二个{姓名:'B',取决于:['A']}。它将查看complete_dependencies数据库中的“A”以查看它是否依赖于某些内容。由于没有'A'的依赖,它只会写{Name:'B',CompleteDepends:['A']}。 (2)找不到依赖于'B'的元素,所以它什么都不做。

{Name:'C'相同,取决​​于:['A']} - > {姓名:'C',CompleteDepends:['A']}。

当它读取下一个文件{姓名:'D',取决于:['C']}时,它会发现'C'取决于'A'所以它会写

{姓名:'D',CompleteDepends:['C','A']}

重要提示:它不必检查递归的'A'依赖关系,因为它正在寻找C“CompleteDependencies”,并且所有A依赖关系必须是C完全依赖关系。

当它处理下一个文档{Name:'E',Depends:['D','B']}时,它会看到'D'和'B'完全依赖,它会发现D完全取决于C A和B仅在A中。{姓名:'E',CompleteDepends:['D','B','C','A']}。

现在让我们假设它收到一个新版本的文档'A':{Name:'A',取决于:['Z']}。现在它必须

1)计算'A'的完整依赖关系 - > {姓名:'A',CompleteDepends:['Z']}

2)查看哪些元素依赖于'A'并重新计算其完整的依赖文档。它将重新计算B,C,D,E的完整依赖关系。

让我们来看看另一个案例。假设我们收到文件C的新版本:{姓名:'C',取决于:['Z']}。

(1)它将生成文件{Name:'C',CompleteDepends:['Z']}。

查看哪些元素依赖于C将找到D和E.现在如果它首先计算E它将发现它依赖于D并且因为D在C含义中它将必须首先重新计算D.这是唯一的事情这个功能(2)必须要小心。

为了做到这一点,我认为函数“Recalculate”必须有一个“脏”元素列表,其中包含所有“隐含”列表,并在计算一个元素时被删除。