Reputation: 99
In Neo4j, I want to create a query that returns nodes grouped on common property without altering my graph. For example, if I have the following graph where each person has a property corresponding to his department in the company:
I want my query to return a graph like the following, where the nodes are replaced by the property and where the weight of the edges corresponds to the number of relations:
Do you have any idea how to proceed? I looked at APOC nodes collapse without success.
Upvotes: 1
Views: 405
Reputation: 12704
This is the way to return the subgraph using apoc.nodes.collapse.
MATCH (p:Person)-[:R]->(c:Person)
WITH c, collect(p) as subgraph
CALL apoc.nodes.collapse(subgraph,{properties:'combine', countMerge:false})
YIELD from, rel, to WHERE to is not null
RETURN from, rel, to
Result:
Creating the nodes WITH relationship weights can be done this way. Unfortunately, apoc.nodes.collapse is not returning relationship weights that you described. But apoc.collapse can count the number of nodes that are merged using countMerge:true.
MATCH (p:Person)-[:R]->(c:Person)
WITH c, collect(p) as subgraph, count(distinct p) AS relweight
WITH c.department as relto, [s in subgraph|s.department][0] as relfrom, relweight
MERGE (d1:Department {name: relfrom})
MERGE (d2:Department {name: relto})
MERGE (d1)-[r:newR{wt: relweight}]->(d2)
RETURN d1, d2, r
Result:
Upvotes: 1
Reputation: 5385
If you want to "return nodes without altering the graph", the way to go is through so-called virtual nodes and relationships. These are nodes/rels that quack like real ones, but only exist in memory.
any other mechanism (including the collapse), alters the graph.
More on virtual node / rels can be found here : https://neo4j.com/labs/apoc/4.4/virtual/
The above approach can be used with pure Neo4j tools. There are other vizualisation layers (like Graphileon : disclosure I work for them) that offer even more possibilities if you need more advanced interaction.
Upvotes: 1
Reputation: 9284
It is possible using, Cypher as well. I created your graph using the following Cypher query, locally:
MERGE (p:Person{name: 'Alex', department: 'HR'})
MERGE (p1:Person{name: 'John', department: 'HR'})
MERGE (p2:Person{name: 'Kate', department: 'IT'})
MERGE (p3:Person{name: 'Mike', department: 'Sales'})
MERGE (p1)-[:R]->(p3)
MERGE (p1)-[:R]->(p2)
MERGE (p2)-[:R]->(p1)
MERGE (p)-[:R]->(p2)
Now, to convert it into the desired graph, you can try the following Cypher query:
MATCH (p:Person)
WITH distinct p.department AS departmentName
MERGE (d:Department{name: departmentName}) <-- First create all the distinct department nodes
WITH COLLECT(departmentName) AS departments
UNWIND departments AS departmentName
MATCH (p:Person{department:departmentName})
OPTIONAL MATCH (p)<-[:R]-(p1:Person)
WITH departmentName, p1 WHERE p1 IS NOT NULL
WITH departmentName, p1.department AS sourceDepartment, count(distinct p1) AS relCount <-- For each department find out the number of distinct incoming relations, with respect to each department
MATCH (d1:Department{name: departmentName})
MATCH (d2:Department{name: sourceDepartment})
MERGE (d1)<-[:R{count: relCount}]-(d2) <-- Create the relationships between department and store the count in the relationship
To check the department nodes, and verify them, run this:
MATCH (n:Department) RETURN n
In the end, if required you can delete all the Person
nodes, like this:
MATCH (n:Person) DETACH DELETE n
Upvotes: 1