Sreenath S
Sreenath S

Reputation: 35

Get all subgraphs of a particular type in Neo4J

I have a set of nodes and relationships and I want to get subgraph of a particular type for a node. To explain the question, attached the image for the graph.

![enter image description here

Nodes in yellow are connected by nodes in green by a relation "IS_PART_OF". When we look at the above fragment, yellow node "8366854" is connected by 4 green nodes "P10398", "P10398-2", "A0A024" and "P02647" where yellow node "8366931" is connected by 2 green nodes "A0A024" and "P02647". So green nodes "A0A024" and "P02647" are common to both and I could say yellow node "8366931" is a sub of "8366854". This happens only if all green nodes are common to both.

So my query will be a yellow node id say "8366854", which returns all sub yellow nodes (in this case only "8366931").

So in this way for the below fragment, I could say,

1) "8366523" is sub of "8366848"

2) "8366915" not a sub of "8366848" since it doesn't have all green nodes in common.

Upvotes: 2

Views: 537

Answers (2)

ThirstForKnowledge
ThirstForKnowledge

Reputation: 1304

1. Creating your graph:

The first statement creates the nodes, the second the relationships between them.

CREATE
  (Yellow1:Yellow {name: 'Yellow 1'}),
  (Yellow2:Yellow {name: 'Yellow 2'}),
  (Yellow3:Yellow {name: 'Yellow 3'}),
  (Yellow4:Yellow {name: 'Yellow 4'}),
  (Yellow5:Yellow {name: 'Yellow 5'}),
  (Yellow6:Yellow {name: 'Yellow 6'}),
  (Green1:Green {name: 'Green 1'}),
  (Green2:Green {name: 'Green 2'}),
  (Green3:Green {name: 'Green 3'}),
  (Green4:Green {name: 'Green 4'}),
  (Green5:Green {name: 'Green 5'}),
  (Green6:Green {name: 'Green 6'}),
  (Green7:Green {name: 'Green 7'}),
  (Green8:Green {name: 'Green 8'}),
  (Green9:Green {name: 'Green 9'}),
  (Green10:Green {name: 'Green 10'}),
  (Green11:Green {name: 'Green 11'}),
  (Green12:Green {name: 'Green 12'}),
  (Green13:Green {name: 'Green 13'})

CREATE
// upper graph
  (Green1)-[:IS_PART_OF]->(Yellow1),
  (Green2)-[:IS_PART_OF]->(Yellow1),
  (Green3)-[:IS_PART_OF]->(Yellow1),
  (Green4)-[:IS_PART_OF]->(Yellow1),
  (Green3)-[:IS_PART_OF]->(Yellow2),
  (Green4)-[:IS_PART_OF]->(Yellow2),
// lower graph
  (Green5)-[:IS_PART_OF]->(Yellow3),
  (Green6)-[:IS_PART_OF]->(Yellow3),
  (Green5)-[:IS_PART_OF]->(Yellow4),
  (Green6)-[:IS_PART_OF]->(Yellow4),
  (Green7)-[:IS_PART_OF]->(Yellow4),
  (Green8)-[:IS_PART_OF]->(Yellow4),
  (Green7)-[:IS_PART_OF]->(Yellow5),
  (Green8)-[:IS_PART_OF]->(Yellow5),
  (Green9)-[:IS_PART_OF]->(Yellow5),
  (Green10)-[:IS_PART_OF]->(Yellow5),
  (Green11)-[:IS_PART_OF]->(Yellow5),
  (Green12)-[:IS_PART_OF]->(Yellow5),
  (Green8)-[:IS_PART_OF]->(Yellow6),
  (Green13)-[:IS_PART_OF]->(Yellow6);

2. Proposed solution:

2.1 Underlying idea:

For a yellow node "this" compare the amount of relationships to an other yellow node "that" with the amount of all relationships of node "this". If the amount is equal, node "this" is a sub of "that".

2.2 Explanation:

  1. identify all pairs between two yellow nodes
  2. identify all green nodes within the yellow-yellow pairs
  3. count the amount of green nodes within a yellow-yellow pair
  4. identify all relationships of the yellow node under inspection
  5. count the amount of all relationships for the yellow node under inspection
  6. filter those yellow-yellow pairs, where the amount of all relationships is equal to the amount of the pair relationships

2.3 Cypher statement:

//                     |-------------------------------------- (1) ---------------------------------------|
MATCH yellowPairPath = (yellowA:Yellow)<-[pairRelation:IS_PART_OF]-(:Green)-[:IS_PART_OF]->(yellowB:Yellow)
WITH DISTINCT yellowA, yellowB, pairRelation
//            |-------- (2) --------|
WITH yellowA, startNode(pairRelation) AS pairRelations, yellowB
//            |------- (3) ------|
WITH yellowA, count(pairRelations) AS pairRelationAmount, yellowB
//    |---------------------- (4) -----------------------|
MATCH (yellowA:Yellow)<-[allRelations:IS_PART_OF]-(:Green)
//                                |------ (5) ------|
WITH yellowA, pairRelationAmount, count(allRelations) AS allRelationsAmount, yellowB
//      |---------------- (6) ----------------|
  WHERE pairRelationAmount = allRelationsAmount
RETURN yellowA, yellowB;

3. Result:

Regarding your requirements, the result has to be interpreted as "YellowA is a sub of YellowB" for the listed nodes.

╒═══════════════════╤═══════════════════╕
│"yellowA"          │"yellowB"          │
╞═══════════════════╪═══════════════════╡
│{"name":"Yellow 2"}│{"name":"Yellow 1"}│
├───────────────────┼───────────────────┤
│{"name":"Yellow 3"}│{"name":"Yellow 4"}│
└───────────────────┴───────────────────┘

Upvotes: 0

stdob--
stdob--

Reputation: 29167

Actually, the cypher allows you to express this by a sequence of instructions:

  • take the yellow node and take all his green neighbors
  • for each green neighbor to find the yellow and its green neighbors
  • make sure that for the second yellow neighbor, each green neighbor is also the neighbor of the first yellow node

MATCH (Y1:YELLOW)<-[:IS_PART_OF]-(G:GREEN)
WITH Y1, 
     collect(G) AS greens1
UNWIND greens1 AS G
MATCH (G)-[:IS_PART_OF]->(Y2:YELLOW)<-[:IS_PART_OF]-(G2:GREEN) WHERE Y1 <> Y2
WITH Y1, Y2, greens1, 
     collect(G2) AS greens2 
     WHERE SIZE(greens1) > size(greens2) AND 
           ALL(G IN greens2 WHERE G IN greens1)
RETURN Y1, collect(Y2) AS subs

Upvotes: 1

Related Questions