Neo4j:如何在树形图中进行属性值的聚合?

时间:2014-01-08 13:08:43

标签: tree neo4j aggregation

我是Neo4j的新手并且正在玩它,看看我们可以在我们的一个项目中使用它。假设我创建的图表如下:

CREATE (n:PORTFOLIO {NAME:"PF_R", VALUE_RF_A:"0.5"})
CREATE (n:PORTFOLIO {NAME:"PF_A", VALUE_RF_A:"1.0", VALUE_RF_B:"2.0"})
CREATE (n:PORTFOLIO {NAME:"PF_B", VALUE_RF_A:"1.1", VALUE_RF_C:"3.0"})

MATCH (r:PORTFOLIO), (a:PORTFOLIO), (b:PORTFOLIO)
WHERE r.NAME="PF_R" AND a.NAME="PF_A" AND b.NAME="PF_B"
CREATE (r)-[s1:has_sub_pf]->(a), (r)-[s2:has_sub_pf]->(b)
RETURN r,a,b

=>题: 如何更改图形的一个(或更多?)MATCH / SET语句如何使得以下查询返回节点“PF_R”:

MATCH (x:PORTFOLIO) 
WHERE x.NAME = "PF_R" 
AND  x.VALUE_RF_A="2.6" AND x.VALUE_RF_B:"2.0" AND VALUE_RF_C:"3.0"
RETURN x

因此,属性“VALUE_ *”在从树叶到根的树中向上聚合。 更详细:

我希望将属性“VALUE_RF_ *”从叶子向上聚合(添加)到根(或添加到下一个上一级,如果不存在)。具体:名称为“PF_A”的PORTFOLIO节点是一个叶子,因此没有任何更改,但应将属性“VALUE_RF_A”和“VALUE_RF_B”添加到其父级,以便名称为“PF_R”的PORTFOLIO节点具有属性“VALUE_RF_A”并且“VALUE_RF_B”,值为“1.5”(1.0 + 0.5)和“2.0”(尚不存在)。在同一时间(或之后),名称为“PF_B”的(叶)PORTFOLIO节点的属性“VALUE_RF_A”和“VALUE_RF_C”也应该添加到节点“PF_R”的属性中,以便最后一个具有属性“VALUE_RF_A”,“VALUE_RF_B”和“VALUE_RF_C”,值为“2.6”,“2.0”和“3.0”。

哦,顺便说一下: 如果只能在一个语句中完成,而不是每个(根) - >叶子路径,那将是完美的。可能的做法是对树的每个“层”进行这样的聚合,从叶子开始向上到父母。 如果要使用的语句不依赖于属性的特定名称,而只是聚合具有相同名称的那些语句(这是顺便说一句。我有另一个问题:它可以,我会更好)查找树中具有相同名称属性的节点:Neo4J中是否有办法查询“元”/模式信息?)

感谢您的支持!

3 个答案:

答案 0 :(得分:3)

我将您的问题解释为类似于树结构中的节点,如何将更高阶节点上的属性设置为其低阶节点的属性之和。我不确定你是否只关心反映其树叶和树枝总和的根节点,或者你是否需要每个相对上级以反映其下级的总和。你没有说过树的深度(你的例子有一个根和两个叶子)或者树中的任何节点是否可以贡献值还是只有叶子,所以我会给出一个你将拥有的一般答案适用于你的结构。

在其根中对树求和的通用模式可以是

MATCH (root:Root)-[:BRANCH*]->(b) // N.B. label the root so you can better control the starting point of your pattern
WITH root, SUM(b.value) as value
SET root.value = value

如果root还包含您可以执行的值。

SET root.sum = root.value + value

保持root.value完好无损。你必须弄清楚这些节点和值是什么 - 我将在下面假设树中的任何节点,而不仅仅是叶子,都可以有实际值,所以我将保持节点的值与它的相对树的总和。如果求和运算改变了求和值,则在第二次运行时得到不同的结果,这可能是不希望的。

将上级中的直接下级相加的通用模式是相似的,但没有对根的标签限制并删除关系上的变量深度修改器

MATCH (superior)-[:BRANCH]->(inferior)
WITH superior, SUM(inferior.value) as sum
SET superior.sum = superior.value + sum

这个查询在传递上做得不好,因为它只获得了下级的值而不是它们的总和,如果它得到总和,它将获得不同的总和,这取决于这些本地总和的计算顺序 - 趋势是在结构中更深的值松散,因为首先计算更浅的总和。如果用于设置中间节点的总和,则第一个查询的反之亦然,这里的风险是更深嵌套的值首先求和,然后在更浅的总和中表示两次。

要让树中的每个中间节点在任何深度汇总所有它的下级节点,但没有重复计算或丢失值,您可以使用本地求和查询,您只需要强加正确的顺序。一种方法是匹配树中任何深度的所有路径,并且对于这样的路径的每个端节点,将其匹配为本地下级的本地上级(bl以下)。然后收集每个上级的下级,并按路径的长度排序结果,确保首先处理最深入树的模式。然后从下级节点累积正确的总和。如果下层是叶子,他们没有自己的总和所以使用它们的价值,否则使用总和;并且任何节点都缺少值然后使用0.这由COALESCE处理。每个节点的值都包含在它自己的总和中,但这取决于你。通过排序MATCH的结果并通过累积而不是在遍历时但在设置属性时,您可以期望聚合以正确的顺序逐步遍历树。

MATCH path=(r:Root)-[:BRANCH*0..]->(b), b-[:BRANCH]->l
WITH b, length(path) as depth, collect(l) as ls
ORDER BY depth desc
SET b.sum = REDUCE(acc = COALESCE(b.value,0), l IN ls | acc + COALESCE(l.sum, l.value, 0))
RETURN ID(b) AS id, depth, b.sum AS sum

这是尝试查询的sample data set。树中的某些节点具有value属性,而有些节点则没有。

这应该适用于一个或多个树,只需标记根节点。

请勿将数值设置为字符串:"1.0" + "2.0" = "1.02.0"

没有明确命名属性,没有直接的方法可以做到这一点。可能有一些解决方法,但你必须分别提出有关问题的问题。

答案 1 :(得分:0)

在我的示例中,即使没有额外的“sum_value”属性,以下内容也有助于我的解决方案:

MATCH path=(r:ROOT)-[:has_sub_pf*0..]->(p), p-[:has_sub_pf]->l
WITH p, length(path) as depth, collect(l) as ls
ORDER BY depth desc
SET p.value_a = REDUCE(acc = COALESCE(p.value_a,0), x IN ls | acc + x.value_a)
RETURN ID(p) AS id, depth, p.sum_a AS sum

非常感谢!!!

答案 2 :(得分:-1)

按照我上面的上一句话 - 这就是我尝试的(但也没用):

MATCH path=(r:ROOT)-[:has_sub_pf*0..]->(p), p-[:has_sub_pf]->(l:PORTFOLIO)
WITH p, length(path) as depth, sum(l.value_b) as sum_value
ORDER BY depth desc
SET p.value_b=sum_value

备注:从ROOT到(LEAF)叶子PORTFOLIO的每个节点都有一个属性value_a。我将此属性设置为仅针对LEAF的属性,然后尝试使用此语句将它们聚合/添加到根(ok,可能是root需要最后的额外语句,但是对于每个内部节点,都应该有value_a != 0,对吗?)