Aggregating relationship properties on a path - neo4j

I'm trying to to get the SUM of the weights on each path my MATCH finds. Query is below:
START n=node(10200)
MATCH p=(n)-[r*1..5]->(m:Facility)
WITH REDUCE(weights=0, rel IN r : weights + rel.weight) AS weight_sum
WHERE ALL(n in nodes(p) WHERE 1=length(filter(m in nodes(p) : m=n)))
RETURN p AS paths, length(p) AS pc,
(weight_sum / (length(p) * (length(p) / 2))) AS sp;
Every time I run it, I'm getting...
Unknown identifier `p`
If I remove my WITH line (and the weight_sum RETURN value), the query knows what 'p' is and executes just fine. Is there a problem with my query that the value of 'p' is being lost? Is there a better alternative to get the SUM of these relationship properties?

You can just pipe "p" to the next part of the query via the WITH:
START n=node(10200)
MATCH p=(n)-[r*1..5]->(m:Facility)
WITH REDUCE(weights=0, rel IN r : weights + rel.weight) AS weight_sum, p
WHERE ALL(n in nodes(p) WHERE 1=length(filter(m in nodes(p) : m=n)))
RETURN p AS paths, length(p) AS pc,
(weight_sum / (length(p) * (length(p) / 2))) AS sp;

Related

Find shortest path between two nodes with all relationships having the same property value

Consider the following graph:
A --p1--> B --p1--> C --p1--> D
| ^
'--------p2---------'
A, B, C, D are nodes and all relationships have an integer property pid (values: p1, p2, ... pn) that are used to identify a path.
Q: How can I find the shortest path between A and D with only a single path id?
I can query for an absolute value with:
MATCH (w1 {name:"A"}),
(w2 {name:"D"}),
p = shortestPath((w1)-[:N*]->(w2))
WHERE all(r IN relationships(p) WHERE r.pid=3)
RETURN p;`
But pid can be any value that I do not know beforehand (and do not care about). I only care about the fact that pid should be the same for all relationships. Something like this:
MATCH (w1 {name:"A"}),
(w2 {name:"D"}),
p = shortestPath((w1)-[:N*]->(w2))
WHERE all(r IN relationships(p) WHERE r.pid = relationships(p)[0].pid )
RETURN p;`
Ideally you would want the shortest path algorithm itself to check that each relationship in the path has the same value for x, but alternatively you can go one relationship out from your start node and check that the shortest path shares an x value with that first relationship. This will give you one shortest path per neighbor to w1 and you can then return the shortest of those.
MATCH (w1 {name:"A"})
MATCH (w2 {name:"D"})
WITH w1, w2
MATCH (w1)-[first_rel:N]->()
p = shortestPath((w1)-[:N*]->(w2))
WHERE all(r IN relationships(p) WHERE r.x=first_rel.x)
RETURN p, size(p) AS sz ORDER BY sz LIMIT 1
What about this?
Set parameters for key and value e.g. to ‘myField’ and ‘myValue’
And then
MATCH (w1 {name:"A"}),
(w2 {name:"D"}),
p = shortestPath((w1)-[:N*]->(w2))
WHERE all(r IN relationships(p) WHERE r[$key]=$value)
RETURN p;

Can't make reduce work in cypher

In this Cypher query, I want to sum all the weights over paths in a graph:
MATCH p=(n:person)-[r*2..3]->(m:person)
WHERE n.name = 'alice' and m.name = 'bob'
WITH REDUCE(weights=0, rel IN r : weights + rel.weight) AS weight_sum, p
return n.name, m.name, weight_sum
LIMIT 10
In this query, I expect to receive a table with 3 columns: n.name, m.name (identical in all the rows), and weight_sum -- according to the weight sum in the specific path.
However, I get this error:
reduce(...) requires '| expression' (an accumulation expression) (line 3,
column 6 (offset: 89))
"WITH REDUCE(weights=0, rel IN r : weights + rel.weight) AS weight_sum, p"
I obviously miss something trivial. But what?
Shouldn't that be
REDUCE(weights=0, rel IN r | weights + rel.weight) AS weight_sum
(with a pipe instead of a colon) as per the documentation in http://neo4j.com/docs/developer-manual/current/cypher/functions/list/ ?
reduce(totalAge = 0, n IN nodes(p)| totalAge + n.age) AS reduction
Hope this helps.
Regards,
Tom

Finding paths longer than x where the sum of their weights (a property) are more than Y in cypher neo4j

in my neo4j graph DB I have issues and persons as my nodes, and relationships are "links" (issue to issue), and "resource" (issue to person).
I'm interested in finding all paths of issues where the sum of their weights is greater than a threshold y and the overall length of the chain is longer than x.
I'm not sure if the following works, as I think it just gives me issues with 5 links
MATCH (s:Issue)-[rs:links*5..]->(m:Issue)
WITH s, rs, m
unwind rs as r
return s AS source_node,
id(s) AS source_id,
r,
m AS target_node,
id(m) AS target_id
I've tried with count as well but I don't think it is the right way to proceed.
To do this, use REDUCE() to accumulate the weights of relationships. Consider a x = 5 and y = 200:
MATCH (s:Issue)-[rs:links*5..]->(m:Issue) // match depths with 5 (x) or more
WITH REDUCE(weights = 0, rel IN rs | weights + rel.weight) AS total_weight, s, rs, m
WHERE total_weight < 100 // filter by total_weight < y (100)
unwind rs as r
return s AS source_node,
id(s) AS source_id,
r,
m AS target_node,
id(m) AS target_id

Cypher query to give path length as a parameter for variable length relationships which is the result of previous sub query

For the following cypher query , how to limit path length by giving "cnt" as a parameter which is the output of previous query passed to next query using "with" clause.
match ()-[r:contents|next_seq]->(n:word) where r.seqid={seqid}
with count(distinct n) as cnt
match p=((a:word)-[rels:next_seq*cnt]->(b:word))
WHERE ALL( rt in rels WHERE rt.seqid={seqid}
return b.name
At this time, the cypher does not allow to use a variable as the path length.
If you use a version of neo4j >= 3 you can use apoc path expander:
match ()-[r:contents|next_seq]->(n:word) where r.seqid={seqid}
with count(distinct n) as cnt
match (a:word)-[rels:next_seq {seqid: {seqid}}]->(:word))
with distinct a
call apoc.path.expand( a, 'next_seq', '+word', 1, cnt ) yield path
with path WHERE ALL( rt in relationships(path) where rt.seqid={seqid} )
return last(nodes(path)).name as name

How to achieve the following in Cypher query?

I tried the following query # http://goo.gl/Ou2GZG
START s=node(1), t=node(4)
MATCH p=s-[*]-pt--t
WHERE SINGLE (n1 IN nodes(p)
WHERE id(n1)=id(t))
WITH DISTINCT pt AS pts, t
MATCH p=t-[*]-pfn
WHERE NONE (n IN nodes(p)
WHERE id(n)=3 OR id(n)=7)
RETURN DISTINCT pfn AS pf
but I don't want to hard code 3 and 7 in the penultimate line where 3 and 7 are the nodes contained in (pts). I tried the following but I am getting "Unclosed parenthesis" error
START s=node(1), t=node(4)
MATCH p=s-[*]-pt--t
WHERE SINGLE (n1 IN nodes(p)
WHERE id(n1)=id(t))
WITH DISTINCT pt AS pts, t
MATCH p=t-[*]-pfn FOREACH(pt in pts :
WHERE NONE (n IN nodes(p)
WHERE id(n)=id(pt)))
RETURN DISTINCT pfn AS pf
I think you can use the ALL predicate to ensures that for each node n in the path p there doesn't exist a node in pt that has the same id as the node n,
START s=node(1), t=node(4)
MATCH p=s-[*]-pt--t
WHERE SINGLE (n1 IN nodes(p)
WHERE id(n1)=id(t))
WITH DISTINCT collect(id(pt)) AS pts, t
MATCH p=t-[*]-pfn
WHERE ALL (n IN nodes(p)
WHERE NONE (pt IN pts
WHERE id(n)= pt))
RETURN DISTINCT pfn AS pf

Resources