質問

I am new to Neo4j and playing arround with it to see wether we can use it in one of our projects. Assume I have graph created as follows:

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

=> Question: How does one (or more?) MATCH/SET statement for changing the graph look like such that the following Query returns me the node "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

So the properties "VALUE_*" are aggregated upwards in the tree from the leaves to the root. In more detail:

I want the attributes "VALUE_RF_*" to be aggregated (added) upwards from the leaves to the root (or added to the next upper level, iff not existing). Concrete: The PORTFOLIO node with name "PF_A" is a leaf so nothing changes there, but the properties "VALUE_RF_A" and "VALUE_RF_B" should be added to its parent such that PORTFOLIO node with name "PF_R" then has properties "VALUE_RF_A" and "VALUE_RF_B" with values "1.5" (1.0+0.5) and "2.0" (not yet existing). Att the same time (or afterwards) the properties "VALUE_RF_A" and "VALUE_RF_C" of the (leaf) PORTFOLIO node with name "PF_B" also should be added to the properties of node "PF_R", so that in the end that one has properties "VALUE_RF_A", "VALUE_RF_B" and "VALUE_RF_C" with values "2.6","2.0" and "3.0".

Oh, Btw: It would be perfect, if this could be done in only one statement and not per (root)->leaf path. May approach would have been to do such an aggregation per "layer" of the tree, starting from the leaves, upwards to the parents. And it would be even nicer, if the statement(s) to be used do not rely on the specific names of the properties, but only aggregate the values of those having the same name (this is btw. another problem I have: Can I find nodes in the tree having properties with the same names: is there a way in Neo4J to query the "meta"/schema-information?)

Thanks for your support!

役に立ちましたか?

解決 3

Following my last remark above - this is what I tried (but that also did not work):

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

Remark: Every node from the ROOT to the (LEAF) leaf PORTFOLIOs has an attribute value_a. I set this attribute to 1 only for the LEAF ones and then tried to use this statement to aggregate/add them up up to the root (ok, may be the root requires a final extra statement, but for every inner node there should be value_a != 0, right?)

他のヒント

I interpret your question to be something like, with nodes in tree structures, how to set properties on a higher order node to the sum of the properties of its lower order nodes. I'm not sure if you only care about a root node reflecting the sum of its leaves and branches, or if you need each relative superior to reflect the sum of its inferiors. You haven't said anything about the depth of your tree (your example has one root and two leaves) or whether any node in the tree can contribute values or only the leaves, so I'll give a general answer that you'll have to apply to your structure.

A generic pattern to sum a tree in its root could be

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

If the root also contains a value you could do.

SET root.sum = root.value + value

leaving root.value intact. You'll have to figure out what these nodes and values are–I'll assume in the following that any node in the tree, not just the leaves, can have real values, so I'll keep the value of a node separate from the sum of its relative tree. If the sum operation alters the values summed it gives different results on the second run, which is probably not desired.

A generic pattern to sum the immediate inferiors in a superior would be similar, but without the label restriction on the root and removing the variable depth modifier on the relationship

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

This query doesn't do a good job transitively, since it only gets the value of inferiors not their sums, and if it were to get the sums it would get different sums depending on the order in which these local sums where calculated–the tendency would be to loose values deeper in the structure because the more shallow sums are calculated first. The reverse is true for the first query if used to set the sums of intermediate nodes, here the risk is that the more deeply nested values are summed first, and are then represented twice in the more shallow sums.

To get each intermediate node in the tree to sum up all it's subordinate nodes at any depth but without double counting or losing values you can use the local summing query, you just need to impose the correct order. One way to do that is to match all the paths of any depth in the tree, and for each end node of such a path match it as a local superior to its local inferiors (b and l below). Then collect the inferiors per superior, and order the results by the length of the path, ensuring that the patterns that are deepest into the tree are handled first. Then accumulate the correct sum from the inferior nodes. If the inferiors are leafs they have no sum of their own so use their value, otherwise use the sum; and any node is missing value then use 0. This is handled by COALESCE. The value of each node is here included in its own sum, but that's up to you. By ordering the results of the MATCH and by doing the accumulation not when traversing but when setting the property, you can expect the aggregation to step through the tree in the correct order.

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

Here's a sample data set to try the query on. Some nodes in the tree have the value property and some don't.

This should work for one or many trees, just label the root nodes.

Don't set numeric values as strings: "1.0" + "2.0" = "1.02.0".

There is no straightforward way to do this without explicitly naming the properties. There may be some workaround, but you'd have to ask questions about that separately.

In my example the following helped to get my solution, even without the extra "sum_value" property:

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

Thank you very much !!!

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top