4

I have a type hierarchy represented in a Neo4j database. All types have one or more :parent relationships which point to other types. The root of the hierarchy has a :parent relationship to itself.

All other nodes in the database have one or more :type relationships which point to a type node. Here is a simple example where the root of the type hierarchy is entity:

Schema

  • rat -[:parent]-> rodent
  • rodent -[:parent]-> animal
  • dog -[:parent]-> animal
  • animal-[:parent]->entity
  • pet -[:parent]-> entity
  • entity -[:parent]-> entity

Now say I have a node representing my pet rat Larry. The node has :type relationships to both pet and rat:

  • Larry-[:type]->pet
  • Larry-[:type]->rat

However, under the defined rules of the hierarchy, Larry's types include not only pet and rat, but also rodent and entity.

Question

I want to generate a query for any type such that it returns all nodes of that type according to the hierarchy. Clearly looking for directly connected nodes does not work-- I tried a few things using -[:type:parent*]-> relationships to match paths of arbitrary length to the target, but the query times were unacceptably long. What is a performant way to implement the above?

Sean Mackesey
  • 10,701
  • 11
  • 40
  • 66

1 Answers1

2

I think model-wise you've got exactly the right idea there. Performance wise this should be quite good, if you write the query reasonably.

Simple cypher ought to be able to do this:

MATCH (larry {name: "Larry"})-[:type:parent*]->(intermediateTypes)-[:parent]->(rootType { label: "ROOT" })
RETURN intermediateTypes;

This stops looking at the top, and gets everything in the middle.

Note that this query could be quite complex and could run a long time if you have multiple inheritance within your type tree, or if it's just not a tree at all...in this case in a big graph cypher could spend quite a while chasing its tail around looking for a path to the root, if for example there were edges saying something like (animal)-[:parent]->(rat). That would be a problem with your data though rather than cypher. In that case, you might want to instead match a shortestPath from Larry to the root type.

FrobberOfBits
  • 17,634
  • 4
  • 52
  • 86
  • Thanks-- this returns all types for a node (except the root), but how do I return all the nodes for a type? The query should also work if I provide the root as the type. – Sean Mackesey Apr 30 '15 at 18:01
  • Just remove the `-[:parent]->(rootType)` part of the query, so that intermediateTypes will include the intermediates and the root. – FrobberOfBits Apr 30 '15 at 18:26
  • OK, that gives all the types for a node, but how do I get the *nodes* given a *type*? I might just not get it, but from what I can tell there is not a simple adaptation of your query that does this. If you post a query that shows clearly where to insert the type name (you used "label" for this, which is fine) so as to get all its nodes, I'll accept the answer. – Sean Mackesey Apr 30 '15 at 19:42