Hi folks,
I’m looking for recommendations on the best way to use an OWL/SHACL ontology as the single source of truth in a Python application backed by Neo4j.
Is there any proven approaches or Python stacks for representing ontology concepts as application-layer classes, validating entities and relationships against ontology constraints, and keeping the Neo4j graph model aligned with the ontology. Has anyone implemented this successfully or found a stack that works well in practice? So basically I'm looking for a single source of truth in my application layer.
If you're attempting to set up a schema against nodes - the approach is going to be highly custom.
If you're attempting to set up a schema against relationships - you will need a mapper between SHACL and CYPHER.
Kurt Cagle did some RDF - CYPHER comparison back in March so you can see the nuisances: RDF 1.2 vs. Neo4j/OpenCypher - by Kurt Cagle
Hi joshcornejo,
Thank you for your response.
I just wanna to clarify my question, it’s about data modeling.
If we want the Domain layer to be modeled with respect to the ontology, I’m thinking of something conceptually similar to Clean Architecture:
my_kg/
├── schema/ # ontology + SHACL
├── domain/ # Pydantic models (should respect the schema)
└── infra/ # Neo4j adapter (neosemantics plugin)
The goal is for the objects instantiated in domain to be ontology-aware, respecting cardinality and value constraints, so that when they’re persisted they become proper individuals in Neo4j with inference, relations, and semantic consistency preserved.
The persistence side is already solved through neosemantics plugin.
The open question is really about the “single source of truth” and the best practice for implementing this cleanly.
Would something like LinkML be the right approach here? https://linkml.io/
Or is the better pattern to define individuals directly in RDF/OWL, use neosemantics to ingest them into Neo4j, and then generate the corresponding Pydantic models from the ontology/schema using some tools or libraries in order for us to be able to create instance of this domain as a python pydantic objects?
I’m curious whether you’ve wired this up end-to-end in a production codebase, and how the layering ended up looking in practice.
If you are thinking of enforcing the schema from the code's perspective (python?) linkml is as good as anything (you could also do it in JSON, XML, RDF, etc) .
If you want the schema in Neo4J to use it to generate a schema - then that could also work.
Neither approach is wrong ... that said if schemas are so important i would use an object oriented programming language that enforces schema within the language (albeit not flexible with schema changes, but the reality should be that schema changes are infrequent).