简体   繁体   中英

Traverse trough the graph with a list of labels in Neo4j

I have this graph:

CREATE (a:Class {brickClass: 'Building',id:"building1"})
CREATE (b:Class {brickClass: 'Air Handler Unit', id:"ahu1"})
CREATE (c:Class {brickClass: 'Cooling System', id:"cools1"})
CREATE (d:Class {brickClass: 'Heat Exchanger', id:"heatex1"})
CREATE (e:Class {brickClass: 'Heat Exchanger', id:"heatex2"})
CREATE (f:Class {brickClass: 'Heat Exchanger', id:"heatex3"})
CREATE (g:Class {brickClass: 'Pump', id:"pump1"})
CREATE (h:Class {brickClass: 'Pump', id:"pump2"})
CREATE (i:Class {brickClass: 'Pump', id:"pump3"})
CREATE (a)-[r:has_equipment]->(b)
CREATE (a)-[s:has_equipment]->(c)
CREATE (b)-[t:has_equipment]->(d)
CREATE (b)-[u:has_equipment]->(e)
CREATE (c)-[w:has_equipment]->(f)
CREATE (d)-[v:has_equipment]->(g)
CREATE (e)-[x:has_equipment]->(h)
CREATE (f)-[y:has_equipment]->(i)

I would like to return all the pumps that is under a heat exchanger, which again is under a air handler unit, that is under a building. So the input is this path:

["Building","Air Handler Unit","Heat Exchanger","Pump"]

I have tried to code this and the result is this code:

WITH ["Building","Air Handler Unit","Heat Exchanger","Pump"] AS labels
UNWIND range(0, size(labels)-1) AS i
WITH labels[i] AS label1, labels[i+1] AS label2, i, labels
match (n:Class{brickClass:label1})-[*..]->(node2:Class{brickClass:label2})
WHERE i + 1 = size(labels) - 1
RETURN node2.id

This code does not return what I want. This code return all the pumps. But I would like it to return only pump1 and pump2. How can I change the code to do that? The labels list could have varying length and labels, so I can not do any hardcoding.

There is no such built-in capability in Neo4j. However with a bit of imagination using APOC you can achieve your result.

What we will do is we will generate what the Cypher query would look like if you could write it by hand, so based on your examples with your 4 items in the parameters the query would look like this:

MATCH path=(:`Class` {brickClass: "Building"})-[:has_equipment]->(:`Class` {brickClass: "Air Handler Unit"})-[:has_equipment]->(:`Class` {brickClass: "Heat Exchanger"})-[:has_equipment]->(:`Class` {brickClass: "Pump"}) RETURN path

To generate the query based on input elements, we will use some string functions in APOC, mainly apoc.text.join

WITH ["Building","Air Handler Unit","Heat Exchanger","Pump"] AS parts

// convert any item in list above into (:Class {brickClass: <value>})

WITH [x IN parts | apoc.text.format('(:`Class` {brickClass: "%s"})', [x])] AS parts


// start the query with `MATCH path=`, 
// add the query parts from above joined by the relationship type 
// and end with `RETURN path`

WITH 'MATCH path=' + apoc.text.join(parts, '-[:has_equipment]->') + ' RETURN path' AS query

RETURN query

This will return the following query string

MATCH path=(:`Class` {brickClass: "Building"})-[:has_equipment]->(:`Class` {brickClass: "Air Handler Unit"})-[:has_equipment]->(:`Class` {brickClass: "Heat Exchanger"})-[:has_equipment]->(:`Class` {brickClass: "Pump"}) RETURN path

Now we can use another APOC function, apoc.cypher.run that allows us to execute a generated query and it returns a single value called.. value

WITH ["Building","Air Handler Unit","Heat Exchanger","Pump"] AS parts
WITH [x IN parts | apoc.text.format('(:`Class` {brickClass: "%s"})', [x])] AS parts
WITH 'MATCH path=' + apoc.text.join(parts, '-[:has_equipment]->') + ' RETURN path' AS query
CALL apoc.cypher.run(query, {})
YIELD value
RETURN value

And the result is what you expect

在此处输入图像描述

Now let's try the same for your example with 2 elements only

WITH ["Heat Exchanger", "Pump"] AS parts
WITH [x IN parts | apoc.text.format('(:`Class` {brickClass: "%s"})', [x])] AS parts
WITH 'MATCH path=' + apoc.text.join(parts, '-[:has_equipment]->') + ' RETURN path' AS query
CALL apoc.cypher.run(query, {})
YIELD value
RETURN value

And the result is there as well, so very dynamic

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM