cancel
Showing results for 
Search instead for 
Did you mean: 

Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.

Beneficial owners - Calculating on relationships properties of paths

Hi, I am new to Neo4j but have handled graphs in R (igraph) for years. I would like to move some of my R logic into cypher, like the case in the picture above. In this case, which is a network of ownership of companies, that could be own by other companies but in the end there are persons that are the real owners of a given company. For the company "A" I want to nest the ownership "pct" to all persons end nodes and calculate the ownership share along the paths.

The follwing query might be a good starting point:

Match (p:Pers) -[r:OWNS*0..]  -> (n:Comp {name: 'A'} )
,path = (p) - [r:OWNS*0..]  -> (n:Comp {name: 'A'} )
return path

that gives me a row for each person a path to A

name    pct   val name1  pct1  val1 name2
  <chr> <int> <int> <chr> <int> <int> <chr>
1 P4      100   150 F        10    100       A    
2 P5       10   100 A        NA      NA      NA   
3 P2       30    30 D        70      100      A    
4 P1       70    30 D        70      100      A    
5 P3      100    10 E        10      100      A    

The ownership share for for row 3 (P2) would be pct(pct1/100) ->30(70/100) = 21

So the question is how to iterate through all rows, get the pct values and perform the calculations.
I have tried with variuos approches with "WITH" AND "UNWIND" but no luck so far.
Below is a script for cerating the sample graph for reusability.

Thanks,
Roger

MERGE (a:Comp {name: 'A', val: 100})
MERGE (b:Comp {name: 'B', val: 1000})
MERGE (c:Comp {name: 'C', val: 70})
MERGE (d:Comp {name: 'D', val: 30})
MERGE (e:Comp {name: 'E', val: 10})
MERGE (f:Comp {name: 'F', val: 150})
MERGE (g:Comp {name: 'G', val: 200})
MERGE (p1:Pers {name: 'P1'})
MERGE (p2:Pers {name: 'P2'})
MERGE (p3:Pers {name: 'P3'})
MERGE (p4:Pers {name: 'P4'})
MERGE (p5:Pers {name: 'P5'})
MERGE (d)-[:OWNS {pct: 70}]-(a)
MERGE (e)-[:OWNS {pct: 10}]-(a)
MERGE (e)-[:OWNS {pct: 100}]-(b)
MERGE (f)-[:OWNS {pct: 10}]-(a)
MERGE (p5)-[:OWNS {pct: 10}]-(a)
MERGE (p5)-[:OWNS {pct: 100}]-(c)
MERGE (p1)-[:OWNS {pct: 70}]-(d)
MERGE (p2)-[:OWNS {pct: 30}]-(d)
MERGE (p3)-[:OWNS {pct: 100}]-(e)
MERGE (p4)-[:OWNS {pct: 100}]-(f)
1 ACCEPTED SOLUTION

Thanks for the detail and sample graph, that makes this much easier.

Since you know :Person nodes and a single :Company node are the endpoints of your pattern, you can match using a variable-length path as you used before.

You don't actually need the second part, the first line is enough (though we'll need the path variable in there).

Using the path variable, we have access to relationships(path), which is a list of all the relationships on the path.

We can use the reduce function to deal with an accumulation of values from the relationships of the path.

Here's the query that will work for all persons and Company A:

MATCH path = (p:Pers) -[:OWNS*0..]  -> (n:Comp {name: 'A'} )
RETURN p.name as name, reduce(total=100.0, rel in relationships(path) | total * (rel.pct / 100.0)) as totalPercent

View solution in original post

2 REPLIES 2

Thanks for the detail and sample graph, that makes this much easier.

Since you know :Person nodes and a single :Company node are the endpoints of your pattern, you can match using a variable-length path as you used before.

You don't actually need the second part, the first line is enough (though we'll need the path variable in there).

Using the path variable, we have access to relationships(path), which is a list of all the relationships on the path.

We can use the reduce function to deal with an accumulation of values from the relationships of the path.

Here's the query that will work for all persons and Company A:

MATCH path = (p:Pers) -[:OWNS*0..]  -> (n:Comp {name: 'A'} )
RETURN p.name as name, reduce(total=100.0, rel in relationships(path) | total * (rel.pct / 100.0)) as totalPercent

Perfect!
Thanks for the help Andrew.

br
Roger