Reputation: 9537
Is there some way to model type hierarchies in Neo4j? If for example I want to build a class hierarchy of cars, I might have a base type of "Car" and then have sub classes that extend that, like "SportCar", etc.
I'd like to be able to create instances of "SportCar", but run a query to get all "Car"s. Is this possible? If so what is the technique?
I think what I'm trying to do is create a "label hierarchy" - but I just don't think that's supported in neo4j.
Upvotes: 15
Views: 9636
Reputation: 31959
You could consider composition in place of inheritance.
CREATE (c0:Car:SportsCar {colour: "yellow", brand: "Bugatti", country: "France"}),
(c1:Car:LuxuryCar {colour: "red", brand: "Mercedes-Benz", country: "Germany"})
Car
sMATCH (c:Car) RETURN c;
SportCar
s:MATCH (c:Car:SportsCar) RETURN c;
LuxuryCar
s:MATCH (c:Car:LuxuryCar) RETURN c;
Upvotes: 2
Reputation: 947
There are at least two ways to do that:
1) Use multiple lables for each object
CREATE(BMW325d:Car:PassengerCar:DieselCar)
CREATE(Porsche911:Car:SportsCar:...)
2) Create an Ontology
The second way of modeling a class hierarchy is using ontologies. Although Neo4j models data as a property graph and ontologies are more suitible for RDF Triple Stores there are ways to use them.
You can create the ontology using Protégé (Open Source). Then you save the Ontology in an .owl-File and upload it to Neo4j using this Plugin. Afterwords you assert your nodes in Neo4j to the Metagraph created in Protégé. A more detailed description is described here.
more on this topic...
For your purposes an RDF Triple Store is an interesting option, escpecially if you want to add semantics to your data like to use inferences and inheritance. I recommend to take a closer look on RDF Triple Stores, which are also graphs - but they store data in triples (subject - predicate - object) instead of nodes and relations. Top Braid Composer is an "easy-to-learn"-tool to get started with them.
Although, I hope that the gap between Property Graphs and RDF triple stores will get smaller soon at the moment it is a tradeoff. SO you should carefully set your requirements on the database before choosing one of them.
Hope this helps.
Upvotes: 11
Reputation: 9537
So the closets thing I could come up with is this example.
Step 1: Create a type hierarchy of car types.
create (c:CarType{Code:"Car"})
create (sc:CarType{Code:"SportCar"})
create (sc)-[:SubCarOf]->(c)
Step 2: Create an instance of a "SportCar" and record that (via a relationship property) it's "CarType".
merge (sc:CarType{Code:"SportCar"})
create (i:SportCar)
create (i)-[:CarType]->(sc)
Step 3: Write a query that finds all "CarType"s that derive from "Car" and any that are just of type "Car", then find instances of these.
match (c)-[:CarType]->(ct:CarType{Code:"Car"})
return c as Car
union
match (sct)-[:SubCarOf*]->(ct:CarType{Code:"Car"}),
(c)-[:CarType]->(sct)
return c as Car
Upvotes: 3
Reputation: 2272
Paul,
First, I'd recommend that you read "Graph Databases", a free O'Reilly e-book available at this link.
As a quick stab at an answer, there are numerous ways to do this sort of thing, and the best choice depends on the problem you are trying to solve. One way would be to construct a "Car" node, then relate your "SportCar" nodes to the "Car" node with a typed relationship like
CREATE (m:Car)
MATCH (m:CAR) WITH m CREATE (n:SportCar)-[:IS_A]->(m)
and create other types of cars, also relating them to the Car node.
You can then find all cars via
MATCH (m:Car)<-[:IS_A]-(n) RETURN n
You can also just put Car and SportCar (and LuxoCar, etc) labels on each node. And that's just two of many approaches.
Grace and peace,
Jim
Upvotes: 14