Cypher Connect nodes in a path returned by gds.alpha.kShortestPaths.stream - neo4j

I run gds.alpha.kShortestPaths.stream using Neo4j 4.0.2. The algorithm yields a path.
The path has the nodes connected with NEXT relationship. I need to find the actual relationships in the Graph that connect the nodes in the path. I came up with a kludgy query that is based on my knowing how long the path is:
...
YIELD path
with nodes(path) as nodes with nodes[0] as n0, nodes[1] as n1, nodes[2] as n2, nodes[3] as n3
match (n0)-[r1]-(n1)
match (n1)-[r2]-(n2)
match (n2)-[r3]-(n3)
return n0, n1, n2, n3, r1, r2, r3
Obviously this solution is inadequate and the only reason I posted it here is to illustrate what I need to do for a path of any length.
Thank you

You can do this programmatically with:
YIELD index, path
WITH index, nodes(path) as nodes
WITH index, nodes, size(nodes) as number_of_nodes
UNWIND range(0,number_of_nodes - 2) as start
WITH index, nodes[start] as start_node, nodes[start + 1] as end_node
MATCH (start_node)-[r:NEXT]->(end_node)
RETURN index, start_node,r, end_node

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 - Cypher: shortest path between multiple nodes

Let's say we have 4 nodes:
{id:1, name:"one"}
{id:2, name:"two"}
{id:3, name:"three"}
{id:4, name:"four"}
Suppose node 1 is linked to node 2, node 2 to 3, 3 to 4 so the result would be something like:
(1)-->(2)-->(3)-->(4)
How would I be able to get the shortest path between multiple given nodes in any given order? A few examples:
findShortestPath(2,4,3) should result in: (2)-->(3)-->(4)
findShortestPath(3,1) should result in: (1)-->(2)-->(3)
findShortestPath(4,1) should result in: (1)-->(2)-->(3)-->(4)
findShortestPath(3,2) should result in: (2)-->(3)
I have tried something like this, but I feel like I'm going the wrong way and it's not the most performant solution. Note that my query gets constructed programmatically since it can contain any number and kind of nodes.
If the input would be: (2),(3),(1)
That would result in a double for loop constructing something like this:
match p=allShortestPaths((p2)-[*]-(p3)),allShortestPaths((p2)-[*]-(p1)),allShortestPaths((p3)-[*]-(p1)) where p1.name="Keanu Reeves" and p2.name="Gene Hackman" and p3.name="Clint Eastwood" return p;
My problem is that I can't provide multiple nodes to the allShortestPaths() function. Only 2 nodes with 1 relation is allowed.
You can go through all the pairs of nodes, and check that the other nodes are in the possible paths between these pairs:
WITH ["Keanu Reeves", "Gene Hackman", "Clint Eastwood"] AS names
UNWIND names AS nn
MATCH (n {name: nn})
WITH collect(n) AS nds
UNWIND nds AS n1
UNWIND nds AS n2
WITH nds, n1, n2 WHERE id(n1) > id(n2)
MATCH path = allShortestPaths((n1)-[*]-(n2))
WITH nds, path WHERE ALL(n IN nds WHERE n IN nodes(path))
RETURN path ORDER BY length(path) ASC

Neo4J - Cypher: allShortestPaths through multiple nodes of multiple labels

Through my question here and the information here, I was able to create a query for my situation. However, when I tested my solution, it seemed that nodes of multiple labels would not return the desired output.
Let's say, Keany Reeves acted in The Matrix and Keanu Reeves knows Clint Eastwood and Clint Eastwood knows Hugh Jackman. In that case, if I were to use this query:
WITH ["Keanu Reeves", "Matrix", "Hugh Jackman"] AS names
UNWIND names AS nn
MATCH (n {name: nn})
WITH collect(n) AS nds
UNWIND nds AS n1
UNWIND nds AS n2
WITH nds, n1, n2 WHERE id(n1) > id(n2)
MATCH path = allShortestPaths((n1)-[*]-(n2))
WITH nds, path WHERE ALL(n IN nds WHERE n IN nodes(path))
RETURN path ORDER BY length(path) ASC;
The desired output would be a node of Keanu Reeves pointing to a node of The Matrix. Then Also pointing to Keanu Reeves would be Clint Eastwood's node. Clint's node would be pointing to Hugh Jackman's node. Something like this:
(HJ)-KNOWS->(CE)-KNOWS->(KR)-ACTED_IN->(TM)
However, my current output does not contain my 3 starting nodes. I think I don't understand the double unwind completely. Is it like a double for loop where you compare to the next item sorted by id?
Btw, in my real life situation, I use id's instead of names, but that doesn't matter for this case. I solve that with a WHERE ID(bla) clause.

Get nodes BETWEEN two nodes

How can I get the nodes on a path of variable length between two nodes, exclusive, in Neo4j?
Example
N1 -RELATIONSHIP-> N2 -RELATIONSHIP-> N3 -RELATIONSHIP-> N4
I'd like to get N2 and N3
I do not know the length of the path beforehand, I only know the starting node
Match p= (n1)-[r:RELATIONSHIP*]->(n4) return filter(x IN nodes(p)
WHERE x<>n1 AND x<>n4) AS pathNodes
try this
You can get all the nodes with in the path like this
MATCH p=(n1)-->(b)-->(n4)
RETURN filter(x IN nodes(p)
WHERE id(x) <> id(n1) AND id(x) <>id(n4)) AS allNodes
Here is the reference doc http://neo4j.com/docs/stable/query-functions-collection.html

Cypher query to check node connectivity

I'm new to neo4j and would really appreciate your help for this.
I have following graph created in neo4j.
n1----n2----n3----n4---n5
n1,n2,n3,n4,n5 all are nodes
--- : relationship_type_1 (REL)
Now given any set of nodes (in any order), I want to check whether these nodes are connected or not.
E.g. Given n1, n2, n3 ==> Connected.
Given n1, n3, n2, n4, n5 ==> Connected.
How should I formulate my cypher query to check connectivity?
Following query is working even if I change the order,
MATCH p=_1--_2--_3
WHERE _1.name?="Node1" and ALL (n in nodes(p)
WHERE n.name IN ["Node1", "Node2", "Node4"])
RETURN nodes(p);
on http://console.neo4j.org/?id=xl8pnl
but if I provide start nodes instead of using _1,_2 and change the order then it's not returning me the path. :(
http://console.neo4j.org/?id=xl8pnl
for following query,
START p1=node(6),p2=node(5),p3=node(4) MATCH p=p1--p2--p3
WHERE p1.name?="Node1" AND ALL (n IN nodes(p) WHERE n.name IN ['Node1' ,'Node3', 'Node2' , 'Node4'])
RETURN nodes(p)
it doesn't return the path as nodes are connected in node(6)-node(5)-node(4) order.
You need to list the different patterns that constitute the "connectedness" to you for instant by listing them explicitly like
console.neo4j.org/r/2w3poz
START p1=node(0),p2=node(4),p3=node(5)
RETURN
CASE
WHEN p1--p2--p3 OR p2--p1--p3 OR p1--p3--p2 OR p3--p2--p1 OR p3--p1--p2
THEN 'Connected'
ELSE 'Not connected'
END
Case 1:
2 paths found
MATCH p=_1--_2--_3--_4
WHERE _1.name?="Node1" and
ALL (n in nodes(p)
WHERE n.name IN ["Node1", "Node2", "Node3", "Node4"])
RETURN nodes(p);
Check it out here:
http://console.neo4j.org/?id=nn9yl6
in this case order dosen't matter
Case 2
(no path found)
Use node 1,2,4
MATCH p=_1--_2--_3
WHERE _1.name?="Node1" and ALL (n in nodes(p)
WHERE n.name IN ["Node1", "Node2", "Node4"])
RETURN nodes(p);
Check it out here:
http://console.neo4j.org/?id=xl8pnl

Resources