Search code examples
graphneo4jcypher

Neo4j - Retrieve nodes of graph components


I have the following graph structure in neo4j.

enter image description here

As you can see, there are two components in this graph. I want to retrieve the blue nodes (nodes of type NodeA in the example) with their respective component. For the example, 4, 3, 2, 1 and 6, 5.

I tried gcc and wcc of neo4j, however it failed, maybe I could not use it properly. Besides, I tried writing custom queries using cypher, however, my results were not even close to the result that I wanted.

You can simulate the graph with the following commands.

CREATE (a:NodeA {name: "1"});
CREATE (a:NodeA {name: "2"});
CREATE (a:NodeA {name: "3"});
CREATE (a:NodeA {name: "4"});
CREATE (a:NodeA {name: "5"});
CREATE (a:NodeA {name: "6"});
CREATE (b:NodeB {anotherName: "11"});
CREATE (b:NodeB {anotherName: "12"});
CREATE (b:NodeB {anotherName: "13"});
CREATE (b:NodeB {anotherName: "14"});
MATCH (a:NodeA {name: "1"})
MATCH(b:NodeB {anotherName: "11"})
CREATE (a) - [:CONTAINS] -> (b);
MATCH (a:NodeA {name: "2"})
MATCH(b:NodeB {anotherName: "11"})
CREATE (a) - [:CONTAINS] -> (b);
MATCH (a:NodeA {name: "3"})
MATCH(b:NodeB {anotherName: "11"})
CREATE (a) - [:CONTAINS] -> (b);
MATCH (a:NodeA {name: "3"})
MATCH(b:NodeB {anotherName: "12"})
CREATE (a) - [:CONTAINS] -> (b);
MATCH (a:NodeA {name: "4"})
MATCH(b:NodeB {anotherName: "12"})
CREATE (a) - [:CONTAINS] -> (b);
MATCH (a:NodeA {name: "5"})
MATCH(b:NodeB {anotherName: "13"})
CREATE (a) - [:CONTAINS] -> (b);
MATCH (a:NodeA {name: "5"})
MATCH(b:NodeB {anotherName: "14"})
CREATE (a) - [:CONTAINS] -> (b);
MATCH (a:NodeA {name: "6"})
MATCH(b:NodeB {anotherName: "14"})
CREATE (a) - [:CONTAINS] -> (b);

Solution

  • You can do it using the GDS strongly connected components procedure after projecting the relationships as undirected:

    // Project the CONTAINS relationships as undirected so that traversals 
    // disregard the directions
    CALL gds.graph.project(
           'components', 
           ['NodeA', 'NodeB'], 
           {CONTAINS: {orientation: 'UNDIRECTED'}}
    );
    
    // Only show the NodeA nodes using the node:NodeA label predicate
    CALL gds.scc.stream('components', {})
    YIELD nodeId, componentId AS component
    WITH gds.util.asNode(nodeId) AS node, component 
    WHERE node:NodeA 
    RETURN node, component 
    ORDER BY component;
    

    Results using your data:

    +----------------------------------+
    | node                 | component |
    +----------------------------------+
    | (:NodeA {name: "1"}) | 0         |
    | (:NodeA {name: "2"}) | 0         |
    | (:NodeA {name: "3"}) | 0         |
    | (:NodeA {name: "4"}) | 0         |
    | (:NodeA {name: "5"}) | 4         |
    | (:NodeA {name: "6"}) | 4         |
    +----------------------------------+