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;
Related
In my project I need to count my node size. Node size is amount of connections with other nodes until depth of 2.
Currently I'm able to do so with two queries:
1. Get ids of all nodes with certain labels:
MATCH (n:Target) RETURN n.Key WHERE <some_where_logic_here>
2. Use returned list of Keys for count
MATCH (n)-[r *0..2]-(b) WHERE n.Key in {keyList} RETURN n.Key as targetId, count(r) as cnt
This works however I wonder if I can get same results with only one query? (like sub select in SQL)
Thanks
Can you try this?
MATCH (n:Target)
WHERE <some_condition>
WITH n
MATCH (n)-[r *0..2]-(b)
RETURN n.Key as targetId, count(r) as cnt
You should be able to do everything with one MATCH. For example:
MATCH (n:Target)
WHERE <some_where_logic_here> AND n.Key in $keyList
RETURN n.Key as targetId, SIZE((n)-[*0..2]-()) as cnt
I am trying to get the shortest path between node (a) and node (c) through a particular node (b) that has the label SomeImportantLabel. Drawn, this is what I want:
(a)-(?..)-(b:SomeImportantLabel)-(?..)-(c)
Note that (?..) means that there might be 'n' number of nodes in between.
Something like this would be the deal I am looking for:
match p = allShortestPaths((a)-[*]-(b:SomeImportantLabel)-[*]-(c))
where id(a) = 123 and id(c) = 456
return nodes(p) as nodes, relationships(p) as rels;
Since it is not possible to have multiple relations in a shortestPath/allShortestPaths function, I have read here on SO that you would have to do it this way:
match p1 = allShortestPaths((a)-[*]-(b:SomeImportantLabel)), p2=allShortestPaths((b:SomeImportantLabel)-[*]-(b))
where id(a) = 123 and id(c) = 456
return nodes(p1)+nodes(p2) as nodes, relationships(p1)+relationships(p2) as rels;
This however gives me way too many nodes that are not even involved and it takes forever to process this query. I think this is because I'm not sure if the same (b) node is used in the 2 allShortestPaths functions.
This would be the result more or less:
/-(v2)
/-(v1)
(a)-(x1)-(b)-(x2)-(c)
\-(y1) \-(z1)-(z2)
The ideal solution would be something like this:
(a)-(x1)-(b1)-(x2)-(c)
\-(b2)-(y1)-(y2)-(c)
This means that there are 2 shortest paths found between (a) and (c) that go through a node (b) with label 'SomeImportantLabel'.
You can use the ANY/ALL/SINGLE/NONE functions to filter path results in the WHERE part, and Neo4j can apply those filters (at least for ALL/NONE if needed) while searching the path.
So for example...
MATCH p = allShortestPaths((a)-[*]-(c))
WHERE ID(a) = 123 AND ID(c) = 456
AND ANY(b in NODES(p) WHERE a<>b<>c AND b:SomeImportantLabel)
RETURN nodes(p) as nodes, relationships(p) as rels;
Also, while we could truncate the head/tail of the list from the filter set of ANY, the Cypher planner likes for the same filter to apply to the whole path, so it's better to exclude them in the WHERE part.
NOT RELEVANT - SKIP TO Important Edit.
I have the following query:
MATCH (n)
WHERE (n:person) AND n.id in ['af97ab48544b'] // id is our system identifier
OPTIONAL MATCH (n)-[r:friend|connected|owner]-(m)
WHERE (m:person OR m:dog OR m:cat)
RETURN n,r,m
This query returns all the persons, dogs and cats that have a relationship with a specific person. I would like to turn it over to receive all the nodes & relationships that NOT includes in this query results.
If it was SQL it would be
select * from graph where id NOT IN (my_query)
I think that the OPTIONAL MATCH is the problematic part. I How can I do it?
Any advice?
Thanks.
-- Important Edit --
Hey guys, sorry for changing my question but my requirements has been changed. I need to get the entire graph (all nodes and relationships) connected and disconnected except specific nodes by ids. The following query is working but only for single id, in case of more ids it isn't working.
MATCH (n) WHERE (n:person)
OPTIONAL MATCH (n)-[r:friend|connected|owner]-(m) WHERE (m:person OR m:dog OR m:cat)
WITH n,r,m
MATCH (excludeNode) WHERE excludeNode.id IN ['af97ab48544b']
WITH n,r,m,excludeNode WHERE NOT n.id = excludeNode.id AND (NOT m.id = excludeNode.id OR m is null)
RETURN n,m,r
Alternatively I tried simpler query:
MATCH (n) WHERE (n:person) AND NOT n.id IN ['af97ab48544b'] return n
But this one does not returns the relationships (remember I need disconnected nodes also).
How can I get the entire graph exclude specific nodes? That includes nodes and relationships, connected nodes and disconnected as well.
try this:
match (n) where not n.id = 'id to remove' optional match (n)-[r]-(m)
where not n.id in ['id to remove'] and not m.id in ['id to remove']
return n,r,m
You've gotta switch the 'perspective' of your query... start by looping over every node, then prune the ones that connect to your person.
MATCH (bad:person) WHERE bad.id IN ['af97ab48544b']
WITH COLLECT(bad) AS bads
MATCH path = (n:person) - [r:friend|:connected|:owner] -> (m)
WHERE n._id = '' AND (m:person OR m:cat OR m:dog) AND NOT ANY(bad IN bads WHERE bad IN NODES(path))
RETURN path
That said, this is a problem much more suited to SQL than to a graph. Any time you have to loop over every node with a label, you're in relational territory, the graph will be less efficient.
It is easy to identify nodes with a certain number of incoming or outgoing relationships, but I want to identify connection redundancies so I want to get a set of all nodes with more than one relationship towards each other.
Pseudo code which unfortunately does not return any results:
MATCH (n1)-[r]-(n2)
with distinct n1,r,n2, count(r) as sstcount
where sstcount > 1
RETURN n1,r,n2
I think I found a solution, the queries need to be correctly linked. Any "nicer solutions" highly appreciated.
MATCH (n1)-[r]-(n2)
WITH distinct n1,n2, count(r) as sstcount
MATCH (n1)-[r]-(n2)
where sstcount>1
return n1,r,n2
Try this one instead:
MATCH (n1)-[r]-(n2)
WHERE id(n1) < id(n2) // so we avoid matching to the same nodes in swapped order
WITH n1,n2, count(r) as sstcount
WHERE sstcount > 1
RETURN n1, n2
I search the longest path of my graph and I want to count the number of distinct nodes of this longest path.
I want to use count(distinct())
I tried two queries.
First is
match p=(primero)-[:ResponseTo*]-(segundo)
with max(length(p)) as lengthPath
match p1=(primero)-[:ResponseTo*]-(segundo)
where length(p1) = lengthPath
return nodes(p1)
The query result is a graph with the path nodes.
But if I tried the query
match p=(primero)-[:ResponseTo*]-(segundo)
with max(length(p)) as lengthPath
match p1=(primero)-[:ResponseTo*]-(segundo)
where length(p1) = lengthPath
return count(distinct(primero))
The result is
count(distinct(primero))
2
How can I use count(distinct()) over the node primero.
Node Primero has a field called id.
You should bind at least one of those nodes, add a direction and also consider a path-limit otherwise this is an extremely expensive query.
match p=(primero)-[:ResponseTo*..30]-(segundo)
with p order by length(p) desc limit 1
unwind nodes(p) as n
return distinct n;