example graph (sorry you need to click the image)
I have a graph with two kinds of nodes:
- identity-nodes as structural elements (blue) holding no attributes
- versioned value-nodes which hold attributes/data (orange)
There are two relation kinds:
- version-of: connects value-nodes to identity-nodes and contains a window within which the relation shall be valid (picture shows just a start date)
- parent-of: connects identity-nodes in a hierarchical fashion
Scenario:
- There is at most one valid value-node per identity-node at any given time.
- I want to keep historical values and look back any time, so copying the values that are currently valid to the respective identity-nodes will not work.
- Hierarchy can be of arbitrary depth, say 1 to 10.
- I wan't to search using fully qualified paths-strings from root to leaf using an attribute of a value-node.
- I want to find the path along ID nodes as well as the right value-of at the end of the path. (Think of a file-system directory path.)
In this example I'm searching for a path "A/CD/E" where A CD E are values of the name property of value-nodes. Basically I want to find the right 'E' node, here the one that is associated to 98. Time is ommited from the examples below to keep them short.
How do I do that? Is that even possible using only Neo4J? (It's easily done wrapping the query in another script that generates a path match including a named id node for each path entry.)
I can query for start and end of the path to limit the search space, but what about a variable number of nodes in between? In a manner of thinking ID nodes would have to be merged with their values matching the time window on the version-of relation before each query.
MATCH p=(start:value) -[:`version-of`]-> (:ID) <-[:`parent-of`*]- (:ID) <-[:`version-of`]- (end:value)
WHERE start.name = 'A' AND end.name = 'E'
RETURN p
What I would like to ask (using variable depth keys instead of the short example); the following is not valid cypher:
MATCH p=(start:value) -[:`version-of`]-> (:ID) <-[:`parent-of`*]- (:ID) <-[:`version-of`]- (end:value)
WHERE p = 'A/CD/E' // or something longer, "A/CD/E/F/X"
RETURN p, end
What I've looked at so far
I can also build the list of names along the path and compare the full paths against the query string. But it can't get the name value for the nodes between start and end:
MATCH p=(start:value) -[:`version-of`]-> (:ID) <-[:`parent-of`*]- (:ID) <-[:`version-of`]- (end:value)
WHERE start.name = 'A' AND end.name = 'E'
RETURN EXTRACT(n in nodes(p)|n['name'])
Subgraph relevant for the query in pairs, but missing the path. Can I get a path of id,val pairs here somehow?
MATCH p=(start:value) -[:`version-of`]-> (:ID) <-[:`parent-of`*]- (:ID) <-[:`version-of`]- (end:value)
WHERE start.name = 'A' AND end.name = 'E'
UNWIND nodes(p) as id
MATCH (id) <-[:`version-of`]- (val)
RETURN COLLECT([id,val])
Here's the graph
MATCH (n) DETACH DELETE n
CREATE (:value {name:'A'}) -[:`version-of` {from:'2017-01-01'}]-> (:ID {id:32})
CREATE (:value {name:'CC'}) -[:`version-of` {from:'2017-01-05'}]-> (:ID {id:21})
CREATE (:value {name:'E'}) -[:`version-of` {from:'2017-02-01'}]-> (:ID {id:98})
CREATE (:value {name:'E'}) -[:`version-of` {from:'2017-02-01'}]-> (:ID {id:48})
MATCH (n:ID {id:21}) CREATE (:value {name:'CD'}) -[:`version-of` {from:'2017-03-01'}]-> (n)
MATCH (a:ID {id:32}),(b:ID {id:21}) CREATE (a)<-[:`parent-of`]-(b)
MATCH (a:ID {id:21}),(b:ID {id:98}) CREATE (a)<-[:`parent-of`]-(b)
MATCH (a:ID {id:32}),(b:ID {id:48}) CREATE (a)<-[:`parent-of`]-(b)