Question

Context : A system where a number of points of interest (pois) are related to each other in multiple hierarchies. A can be B's parent in one hierarchy, while in another hierarchy A can be B's child (or even a further descendant). For this reason the Neo4j graph contains hierarchies and parentchildrelations as seperate nodes, instead of linking pois with [isChildOf] relations.

the graph to illustrate this can be generated using this cypher script. I'm using Neo4j 2.0.0-M06. I've included some labels for readability, but I don't want to rely on them for the queries.

create (_1 {`name`:"Class"})
create (_4:Class {`name`:"Poi"})
create (_5:Class {`name`:"PoiType"})
create (_9:Class {`name`:"Hierarchy"})
create (_10:Class  {`name`:"ParentChildRelation"})
create _4-[:`isA`]->_1
create _5-[:`isA`]->_1
create _9-[:`isA`]->_1
create _10-[:`isA`]->_1
create (_26:PoiType   {`poitypeid`:"2", `name`:"City"})
create (_27:PoiType   {`poitypeid`:"3", `name`:"Province "})
create (_28:PoiType  {`poitypeid`:"4", `name`:"Country"})
create (_29:Poi {`poiid`:"72882",`name`:"Netherlands"})
create (_30:Poi {`poiid`:"126",`name`:"Gelderland"})
create (_31:Poi {`poiid`:"52662",`name`:"Wageningen"})
create (_32:Poi {`poiid`:"8839",`name`:"Ede"})
create _26-[:`isA`]->_5
create _27-[:`isA`]->_5
create _28-[:`isA`]->_5
create _29-[:`isA`]->_4
create _30-[:`isA`]->_4
create _31-[:`isA`]->_4
create _32-[:`isA`]->_4
create _29-[:`isOfType`]->_28
create _30-[:`isOfType`]->_27
create _31-[:`isOfType`]->_26
create _32-[:`isOfType`]->_26
create (_33:Hierarchy {`treeid`:"1",`name`:"GeoAdmin"})
create _33-[:`isA`]->_9
create _33-[:`isOfType`]->_4
create (_34:ParentChildRelation {`pcrid`:"1"})
create _34-[:`isA`]->_10
create _34-[:`belongsTo`]->_33
create _34-[:`relationParent`]->_29
create _34-[:`relationChild`]->_30
create (_35:ParentChildRelation {`pcrid`:"2"})
create _35-[:`isA`]->_10
create _35-[:`belongsTo`]->_33
create _35-[:`relationParent`]->_30
create _35-[:`relationChild`]->_31
create (_36:ParentChildRelation {`pcrid`:"3"})
create _36-[:`isA`]->_10
create _36-[:`belongsTo`]->_33
create _36-[:`relationParent`]->_30
create _36-[:`relationChild`]->_32
create (_37:Hierarchy {`treeid`:"2",`name`:"SomePoiHierarchy"})
create _37-[:`isA`]->_9
create _37-[:`isOfType`]->_4
create (_38:ParentChildRelation {`pcrid`:"4"})
create _38-[:`isA`]->_10
create _38-[:`belongsTo`]->_37
create _38-[:`relationParent`]->_29
create _38-[:`relationChild`]->_32
;

To have an overview of the hierarchical relations, queries like this work fine:

MATCH ptp<-[r4:isOfType]-p<-[r1:relationParent]-pcr-[r2:relationChild]->c-[r5:isOfType]->ptc,pcr-[r3:belongsTo]->h 
RETURN ptp.name,p.name,ptc.name,c.name,h.name

resulting in this:

ptp.name    p.name       ptc.name   c.name          h.name
Country     Netherlands  City       Ede             SomePoiHierarchy
Country     Netherlands  Province   Gelderland      GeoAdmin
Province    Gelderland   City       Ede             GeoAdmin
Province    Gelderland   City       Wageningen      GeoAdmin

As illustration, this is one of the paths that exit in the graph

Nederland <- [relationParent] – pcr(1) – [relationChild] -> Gelderland <- [relationParent] – pcr(2) – [relationChild] -> Wageningen

Question : When I want to get all nodes of a given type in a branch in the hierarchy, I have an undefined number of constructs like

<- [relationParent] – pcr – [relationChild] ->  

in the path.

When using a direct [isChildOf] relation between nodes, I would use something like this

start n=node(84)  
match n<-[r1:IsChildOf*]-m-[r2:IsOfType]->pt
where pt.name="City"
return n,n.name,m,m.name,pt.name

But now I need some syntax that allows me to repeat the entire construct including the relations through the parentchildrelation node.

Who knows how to do this ?

Was it helpful?

Solution

I don't see there is a way in Cypher that can specify a repetition pattern that is consisted of both node and relationships as required in your case. So I am trying to think of it from a different point of view.

My understanding is you introduced a middle node between a pair of a parent and child nodes and this middle node is served as the identity of the hierarchy type of the parent-child relationship. So if you want to find out all descendant nodes of a certain hierarchy, you might start from identifying the middle nodes that belong to the hierarchy, then find all direct child nodes of these middle nodes. This ensures that all these child nodes must be in the desired hierarchy. Furthermore, the middle nodes must have one or more relationships to the desired country node. For example, if you want to find out all descendant city nodes of a country node with the hierarchy of "GeoAdmin" , you can implement the query as follows,

Match m-[:belongsTo]->h 
Where h.name ='GeoAdmin'
With m
Match cityType<-[:isOfType]-city<-[:relationChild]-m-[:relationParent|relationChild*1..6]-country-[:isOfType]->countryType
Where cityType.name ='City' and countryType.name ='Country'
Return distinct city

This would give you the two city nodes with names "Wageningen" and "Ede". (I have restricted the length of pattern up to 6, you might increase the length as whatever fits your case.)

If you want to change the hierarchy to "SomePoiHierarchy", then you just need to change the first Where clause to "Where h.name ='SomePoiHierarchy'", this should give you the city "Ede" only.

I created a console here http://console.neo4j.org/?id=37qf3j based on Michael Hunger's console.

OTHER TIPS

What you can do:

First you had a typo in your relationship-type: "isOfType" starts with a lowercase "i".

this one returned too many results as it also included the ParentChildRelations

MATCH n-[r1:relationParent|relationChild*]-m-[r2:isOfType]->pt 
WHERE pt.name="City" 
RETURN n,n.name,m,m.name,pt.name

That's why I limited it to the :Poi.

MATCH n-[r1:relationParent|relationChild*]-m-[r2:isOfType]->pt 
WHERE pt.name="City" AND n:Poi 
RETURN n,n.name,m,m.name,pt.name

Which returns:

+------------------------------+
| n.name        | m.name       |
+------------------------------+
| "Ede"         | "Wageningen" |
| "Ede"         | "Ede"        |
| "Wageningen"  | "Ede"        |
| "Gelderland"  | "Wageningen" |
| "Gelderland"  | "Ede"        |
| "Netherlands" | "Wageningen" |
| "Netherlands" | "Ede"        |
+------------------------------+
7 rows

http://console.neo4j.org/r/5b1m96

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top