How to get the path with relationships from randomWalk call in Cypher? - neo4j

I am using Neo4j randomWalk algorithm on a base 2 types of nodes (N1 and N2) and one type of relationship (R1).
The random walk algorithm returns a list of NodeId. The issue here is that I'd like to get the relationships R1 between the nodes of each path.
I've tried the following query :
MATCH (n:N1) WHERE ID(n) = 38
CALL algo.randomWalk.stream(ID(n), 4, 4)
YIELD nodeIds
UNWIND nodeIds as nodeId
OPTIONAL MATCH (l:N1)-[r:R1]-(q:N2)
WHERE (ID(l) = nodeId) AND (ID(q) in nodeIds)
RETURN l,q, nodeIds, nodeId,ID(q), ID(l)
However, this is not a good solution cause it is showing every relationships between node l and node q that are present in nodeIds. Hence I don't get the path.
Do you know how could I solve this problem?
Thanks for your time,
Syndorik

After some research, I found a way to get the nth element and nth+1 element in the same UNWIND loop.
This is what I did :
MATCH (n:Clips) WHERE ID(n) = 39
CALL algo.randomWalk.stream(ID(n),4,1)
YIELD nodeIds
UNWIND RANGE(0,size(nodeIds)-1) as idx
MATCH (l)-[r:R1]-(q)
WHERE ID(l) = nodeIds[idx] and ID(q) = nodeIds[idx+1]
RETURN ID(l), ID(q),nodeIds
With this, I successfully retrieved the path with relations and nodes. Do not hesitate if you have some questions on how it works. The image bellow is what I get.

Related

How Many Nodes Are Involved in a Match

How can I know how many nodes and edges are involved in a MATCH? Is there another way besides Explain / Profile Match?
If you mean how many nodes are matched in a path, such as a variable-length path, then you can assign a path variable for this:
MATCH p = (k:Person {name:'Keanu Reeves'})-[*..8]-(t:Person {name:'Tom Hanks'})
WITH p LIMIT 1
RETURN p, length(p) as pathLength, length(p) + 1 as numberOfNodesInPath
You can also use nodes(p) and relationships(p) to get the collection of nodes and relationships that make up the path, and you can use size() on those collections to get their size.
There exists the COUNT() function of Cypher that allows you to count the number of elements. As for example in this query:
MATCH (n)
RETURN COUNT(n);
This query will count all nodes in your database.
You can find more information in the cypher manual, under the aggregating functions. Check it out.
The following Cypher snippet should return the number of distinct nodes and relationships found by any given MATCH clause. Just replace <your code here> with your MATCH pattern.
MATCH <your code here>
WITH COLLECT(NODES(p)) AS ns, SUM(SIZE(RELATIONSHIPS(p))) AS relCount
UNWIND ns AS nodeList
UNWIND nodeList AS node
RETURN COUNT(DISTINCT node) AS nodeCount, relCount;

Neo4j more efficient Cypher query for finding connected nodes with a relationship

I have a patch where I know a starting and end node with an unknown number of nodes between the 2. I wish to collect a collection of nodes and each nodes exiting relationship in the chain.
PROFILE MATCH p = (:Question{id:'1234'})-[:Answer*0..3]->(t)-
[:Answer]->(:Question{id:'5678'})
WHERE t:Set OR t:Read
OPTIONAL MATCH (x)-[v:Answer]->(y)
WHERE x.id <> '1234' and x IN nodes(p) AND v IN rels(p)
return x,v
This query is pretty inefficient as the OPTIONAL MATCH (x)-[v:Answer]->(y) requires a full nodes scan.
I know that t and as a result x will be of types Set or Read which would reduce the scan quite a bit but don't think there is a way to query this.
Is there any way to optimise this?
You can simply unwind the path you have already got:
MATCH p = (:Question{id:'1234'})-[:Answer*0..3]->(t)-[:Answer]->(:Question{id:'5678'})
WHERE t:Set OR t:Read
WITH nodes(p) AS nds,
rels(p) AS rls
UNWIND range(1, length(nds)-2) AS i
RETURN nds[i] AS x,
rls[i] AS v

How to get the neighbor's nodes of a path in neo4j

I have a path and I want to get the nodes that connected to this path by some edges. I wrote this qwery and it's not working properly:
match p=(a)-[:example*]->(c) where length(p) = 5
with p
match (u)-[r:example2]-> p return u,p,r
I want to get all that nodes 'u'.
can you tell me please what i'm doing wrong?
Thanks.
Extract the nodes of the path using the nodes() function, UNWIND the list and then perform the match. You might want to collect the results for each node a.
match p=(a)-[:example*]->(c)
where length(p) = 5
with a, nodes(p) as pathNodes
unwind pathNodes as pathNode
match (u)-[r:example2]->(pathNode)
return a, collect([u, pathNode])

How to eliminate a path where exists a relationship outside of the path, but between nodes in the path?

I have modified the 'vanilla' initial query in this console, and added one relationship type 'LOCKED' between the 'Morpheus' and 'Cypher' nodes.
How can I modify the existing (first-run) query, which is a variable length path so that it no longer reaches the Agent Smith node due to the additional Locked relationship I've added?
First-run query:
MATCH (n:Crew)-[r:KNOWS|LOVES*2..4]->m
WHERE n.name='Neo'
RETURN n AS Neo,r,m
I have tried this kind of thing:
MATCH p=(n:Crew)-[r:KNOWS|LOVES*2..4]->m
WHERE n.name='Neo'
AND none(rel IN rels(p) WHERE EXISTS (StartNode(rel)-[:LOCKED]->EndNode(rel)))
RETURN n AS Neo,r,m
..but it doesn't recognize the pattern inside the none() function.
I'm using Community 2.2.1
Thanks for reading
I'm pretty sure you can't use a function in a MATCHy type clause like that (though it's clever). What about this?
MATCH path=(neo:Crew)-[r:KNOWS|LOVES|LOCKED*2..4]->m
WHERE neo.name='Neo'
AND NOT('LOCKED' IN rels(path))
RETURN neo,r,m
EDIT:
Oops, looks like Dave might have beat me to the punch. Here's the solution I came up with anyway ;)
MATCH p=(neo:Crew)-[r:KNOWS|LOVES*2..4]->m
WHERE neo.name='Neo'
WITH p, neo, m
UNWIND rels(p) AS rel
MATCH (a)-[rel]->(b)
OPTIONAL MATCH a-[locked_rel:LOCKED]->b
WITH neo, m, collect(locked_rel) AS locked_rels
WHERE none(locked_rel IN locked_rels WHERE ()-[locked_rel]->())
RETURN neo, m
Ok, this is a little convoluted but i think it works. The approach is to take all of the paths and find the last known good nodes (ones that have LOCKED relationships leaving them). Then use that node(s) as a new ending point(s) and return the paths.
match p=(n:Crew)-[r:KNOWS|LOVES|LOCKED*2..4]->m
where n.name='Neo'
with n, relationships(p) as rels
unwind rels as r
with n
, case
when type(r) = 'LOCKED' then startNode(r)
else null
end as last_good_node
with n
, (collect( distinct last_good_node)) as last_good_nodes
unwind last_good_nodes as g
match p=n-[r:KNOWS|LOVES*]->g
return p
I think this would be simpler if there was a locked: true property on the KNOWS and LOVES relationships.

Neo4j cypher - Counting immediate children of root nodes

I'm struggling with a problem despite having read a lot of documentation... I'm trying to find my graph root node (or nodes, they may be several top nodes) and counting their immediate children (all relations are typed :BELONGS_TO)
My graph looks like this (cf. attached screenshot). I have been trying the following query which works as long as the root node only has ONE incomming relationship, and it doesn not when it has more than one. (i'm not realy familiar with the cyhper language yet).
MATCH (n:Somelabel) WHERE NOT (()-[:BELONGS_TO]->(n:Somelabel)) RETURN n
Any help would be much appreciated ! (i haven't even tried to count the root nodes immediate children yet...which would be "2" according to my graph)
Correct query was given by cybersam
MATCH (n:Somelabel) WHERE NOT (n)-[:BELONGS_TO]->() RETURN n;
MATCH (n:Somelabel)<-[:BELONGS_TO]-(c:Somelabel)
WHERE NOT (n)-[:BELONGS_TO]->() RETURN n, count(c);
Based on your diagram, it looks like you are actually looking for "leaf" nodes. This query will search for all Somelabel nodes that have no outgoing relationships, and return each such node along with a count of the number of distinct nodes that have a relationship pointing to that node.
MATCH (n:Somelabel)
WHERE NOT (n)-[:BELONGS_TO]->()
OPTIONAL MATCH (m)-[:BELONGS_TO]->(n)
RETURN n, COUNT(DISTINCT m);
If you are actually looking for all "root" nodes, your original query would have worked.
As a sanity check, if you have a specific node that you believe is a "leaf" node (let's say it has an id value of 123), this query should return a single row with null values for r and m. If you get non-null results, then you actually have outgoing relationships.
MATCH (n {id:123})
OPTIONAL MATCH (n)-[r]->(m)
RETURN r, m

Resources