Queries
ontopoiesis query runs Cypher against a .lbug projection and prints the results as a
table. Build the projection first with ontopoiesis build, then query it
repeatedly without re-parsing the source OWL document.
This page is a reference catalogue of Cypher patterns for querying a .lbug
projection by OWL 2 construct category. The sections are organized around common query
tasks: discovery, class hierarchy, property patterns, annotations, individuals, and
other structural lookups. For the graph shape those queries target, see
The Projection Graph Model. For the canonical construct kind names
used in kind filters, see OWL 2 Construct Coverage.
Jump to:
- Discovery
- Class hierarchy
- Object properties
- Property characteristics
- Data properties
- Cardinality restrictions
- Individuals and assertions
- Ontology structure
- Annotation assertions
- SPARQL comparison
- Troubleshooting
Discovery¶
Discover what construct kinds are present in a projection:
On the bundled family ontology:
kind
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Class
Declaration
DisjointClasses
EquivalentClasses
NamedIndividual
NegativeObjectPropertyAssertion
ObjectHasSelf
ObjectIntersectionOf
ObjectProperty
ObjectPropertyChain
ObjectSomeValuesFrom
Ontology
Prefix
SubClassOf
SubObjectPropertyOf
List all named classes:
List all object properties:
Count constructs by kind:
Class hierarchy¶
Named subclass relationships:
MATCH (ax:N {kind: 'SubClassOf'})
-[:E {role: 'sub'}]->(sub:N {kind: 'Class'}),
(ax)-[:E {role: 'super'}]->(sup:N {kind: 'Class'})
WHERE sub.iri IS NOT NULL AND sup.iri IS NOT NULL
RETURN sub.iri AS subclass, sup.iri AS superclass
ORDER BY subclass
Against the family sample ontology, which uses complex class expressions as superclasses, this query returns no rows. On ontologies with direct named-class-to-named-class subclass axioms — like the GO slim — this query returns a row per asserted relationship. See the GO slim example for a worked demonstration.
Classes with no named superclass (root classes):
MATCH (cls:N {kind: 'Class'})
WHERE cls.iri IS NOT NULL
AND NOT EXISTS {
MATCH (ax:N {kind: 'SubClassOf'})
-[:E {role: 'sub'}]->(cls),
(ax)-[:E {role: 'super'}]->(sup:N {kind: 'Class'})
WHERE sup.iri IS NOT NULL
}
RETURN cls.iri AS root_class
ORDER BY root_class
On the bundled family ontology:
root_class
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
http://example.org/Father
http://example.org/Man
http://example.org/Mother
http://example.org/NarcisticPerson
http://example.org/Parent
http://example.org/Person
http://example.org/YoungChild
Named equivalence relationships:
MATCH (ax:N {kind: 'EquivalentClasses'})
-[:E {role: 'operand'}]->(cls:N {kind: 'Class'})
WHERE cls.iri IS NOT NULL
RETURN ax.uid AS axiom, cls.iri AS class
ORDER BY axiom, class
On the bundled family ontology:
axiom class
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
n37 http://example.org/NarcisticPerson
n39 http://example.org/Parent
(uid values like n37 are assigned in document order and are not stable across
rebuilds — filter and join on iri, not uid.)
Classes defined by existential restriction:
MATCH (ax:N {kind: 'EquivalentClasses'})
-[:E {role: 'operand'}]->(cls:N {kind: 'Class'}),
(ax)-[:E {role: 'operand'}]->(restriction:N {kind: 'ObjectSomeValuesFrom'})
-[:E {role: 'property'}]->(prop:N {kind: 'ObjectProperty'})
WHERE cls.iri IS NOT NULL AND prop.iri IS NOT NULL
RETURN cls.iri AS class, prop.iri AS via_property
ORDER BY class
Object properties¶
Sub-property relationships:
MATCH (ax:N {kind: 'SubObjectPropertyOf'})
-[:E {role: 'sub'}]->(sub:N),
(ax)-[:E {role: 'super'}]->(sup:N)
WHERE sub.iri IS NOT NULL AND sup.iri IS NOT NULL
RETURN sub.iri AS sub_property, sup.iri AS super_property
ORDER BY sub_property
Against the bundled family ontology, this query returns no rows because its
SubObjectPropertyOf axioms use property chains rather than named sub-property links.
Property chains — ordered links of a SubObjectPropertyOf chain clause:
MATCH (ax:N {kind: 'SubObjectPropertyOf'})
-[:E {role: 'super'}]->(sup:N),
(ax)-[:E {role: 'sub'}]->(:N {kind: 'ObjectPropertyChain'})
-[link:E {role: 'operand'}]->(step:N)
WHERE sup.iri IS NOT NULL AND step.iri IS NOT NULL
RETURN sup.iri AS property, step.iri AS chain_step, link.position AS position
ORDER BY property, position
On the bundled family ontology:
property chain_step position
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
http://example.org/hasUncle http://example.org/hasFather 0
http://example.org/hasUncle http://example.org/hasBrother 1
Property characteristics¶
Transitive object properties:
MATCH (n:N {kind: 'TransitiveObjectProperty'})
-[:E {role: 'property'}]->(prop:N)
WHERE prop.iri IS NOT NULL
RETURN prop.iri AS property
ORDER BY property
Functional object properties:
MATCH (n:N {kind: 'FunctionalObjectProperty'})
-[:E {role: 'property'}]->(prop:N)
WHERE prop.iri IS NOT NULL
RETURN prop.iri AS property
ORDER BY property
Annotation property domains and ranges:
MATCH (ax:N {kind: 'AnnotationPropertyDomain'})
-[:E {role: 'property'}]->(prop:N),
(ax)-[:E {role: 'domain'}]->(dom:N)
WHERE prop.iri IS NOT NULL
RETURN prop.iri AS property, COALESCE(dom.iri, dom.kind) AS domain
ORDER BY property
MATCH (ax:N {kind: 'AnnotationPropertyRange'})
-[:E {role: 'property'}]->(prop:N),
(ax)-[:E {role: 'range'}]->(rng:N)
WHERE prop.iri IS NOT NULL
RETURN prop.iri AS property, COALESCE(rng.iri, rng.kind) AS range
ORDER BY property
Data properties¶
List all data properties:
Data property domain:
MATCH (ax:N {kind: 'DataPropertyDomain'})
-[:E {role: 'property'}]->(prop:N),
(ax)-[:E {role: 'domain'}]->(cls:N)
WHERE prop.iri IS NOT NULL AND cls.iri IS NOT NULL
RETURN prop.iri AS property, cls.iri AS domain
ORDER BY property
Data property range:
MATCH (ax:N {kind: 'DataPropertyRange'})
-[:E {role: 'property'}]->(prop:N),
(ax)-[:E {role: 'range'}]->(rng:N)
WHERE prop.iri IS NOT NULL
RETURN prop.iri AS property, COALESCE(rng.iri, rng.kind) AS range
ORDER BY property
Data property assertions:
MATCH (ax:N {kind: 'DataPropertyAssertion'})
-[:E {role: 'subject'}]->(src:N),
(ax)-[:E {role: 'property'}]->(prop:N),
(ax)-[:E {role: 'object'}]->(val:N)
WHERE src.iri IS NOT NULL AND prop.iri IS NOT NULL
RETURN src.iri AS source,
prop.iri AS property,
val.text AS value
ORDER BY source, property
Cardinality restrictions¶
Minimum cardinality restrictions in subclass axioms:
MATCH (ax:N {kind: 'SubClassOf'})
-[:E {role: 'sub'}]->(cls:N {kind: 'Class'}),
(ax)-[:E {role: 'super'}]->(card:N {kind: 'ObjectMinCardinality'})
-[:E {role: 'property'}]->(prop:N)
WHERE cls.iri IS NOT NULL AND prop.iri IS NOT NULL
RETURN cls.iri AS class, prop.iri AS property, card.cardinality AS min_count
ORDER BY class, property
Maximum cardinality restrictions:
MATCH (ax:N {kind: 'SubClassOf'})
-[:E {role: 'sub'}]->(cls:N {kind: 'Class'}),
(ax)-[:E {role: 'super'}]->(card:N {kind: 'ObjectMaxCardinality'})
-[:E {role: 'property'}]->(prop:N)
WHERE cls.iri IS NOT NULL AND prop.iri IS NOT NULL
RETURN cls.iri AS class, prop.iri AS property, card.cardinality AS max_count
ORDER BY class, property
Exact cardinality restrictions:
MATCH (ax:N {kind: 'SubClassOf'})
-[:E {role: 'sub'}]->(cls:N {kind: 'Class'}),
(ax)-[:E {role: 'super'}]->(card:N {kind: 'ObjectExactCardinality'})
-[:E {role: 'property'}]->(prop:N)
WHERE cls.iri IS NOT NULL AND prop.iri IS NOT NULL
RETURN cls.iri AS class, prop.iri AS property, card.cardinality AS exact_count
ORDER BY class, property
Has-key axioms:
MATCH (ax:N {kind: 'HasKey'})
-[:E {role: 'class'}]->(cls:N {kind: 'Class'})
WHERE cls.iri IS NOT NULL
RETURN cls.iri AS class, ax.uid AS has_key_axiom
ORDER BY class
Individuals and assertions¶
All named individuals and their explicitly asserted types:
MATCH (ax:N {kind: 'ClassAssertion'})
-[:E {role: 'class'}]->(cls:N {kind: 'Class'}),
(ax)-[:E {role: 'individual'}]->(ind:N {kind: 'NamedIndividual'})
WHERE ind.iri IS NOT NULL AND cls.iri IS NOT NULL
RETURN ind.iri AS individual, cls.iri AS type
ORDER BY individual, type
Against the bundled family ontology, this query returns no rows because the sample focuses on TBox patterns plus a negative assertion rather than positive type assertions.
Object property assertions between named individuals:
MATCH (ax:N {kind: 'ObjectPropertyAssertion'})
-[:E {role: 'subject'}]->(src:N),
(ax)-[:E {role: 'property'}]->(prop:N),
(ax)-[:E {role: 'object'}]->(tgt:N)
WHERE src.iri IS NOT NULL AND prop.iri IS NOT NULL AND tgt.iri IS NOT NULL
RETURN src.iri AS source, prop.iri AS property, tgt.iri AS target
ORDER BY source, property
Against the bundled family ontology, this query returns no rows because the bundled sample contains only the negative form of the assertion.
Negative object property assertions:
MATCH (ax:N {kind: 'NegativeObjectPropertyAssertion'})
-[:E {role: 'subject'}]->(src:N),
(ax)-[:E {role: 'property'}]->(prop:N),
(ax)-[:E {role: 'object'}]->(tgt:N)
WHERE src.iri IS NOT NULL AND prop.iri IS NOT NULL AND tgt.iri IS NOT NULL
RETURN src.iri AS source, prop.iri AS property, tgt.iri AS target
ORDER BY source, property
On the bundled family ontology:
source property target
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
http://example.org/Bill http://example.org/hasD… http://example.org/Sus…
Ontology structure¶
Import declarations recorded in the projection:
Prefix declarations from the source document:
Ontology nodes and their version IRIs:
MATCH (n:N {kind: 'Ontology'})
RETURN n.ontology_iri AS ontology_iri, n.version_iri AS version_iri
ORDER BY ontology_iri
Annotation assertions¶
An AnnotationAssertion has three edges: property (the annotation property),
subject (an IRI node whose text is the annotated entity's IRI), and value (the
annotation value). A literal value is a Literal node — its string is val.text, its
language tag val.lang; an IRI-valued annotation points at an IRI node (also text).
All annotation assertions on a specific entity:
MATCH (ax:N {kind: 'AnnotationAssertion'})
-[:E {role: 'property'}]->(prop:N),
(ax)-[:E {role: 'subject'}]->(subj:N),
(ax)-[:E {role: 'value'}]->(val:N)
WHERE subj.text = 'http://example.org/YourClass'
RETURN prop.iri AS property,
val.text AS value,
val.lang AS lang
ORDER BY property
All rdfs:label annotations across the ontology:
MATCH (ax:N {kind: 'AnnotationAssertion'})
-[:E {role: 'property'}]->(:N {iri: 'http://www.w3.org/2000/01/rdf-schema#label'}),
(ax)-[:E {role: 'subject'}]->(subj:N),
(ax)-[:E {role: 'value'}]->(val:N)
RETURN subj.text AS entity,
val.text AS label,
val.lang AS lang
ORDER BY entity, lang
The derived annotation_value edge collapses this to one hop, joining the labelled
entity node straight to its literal — see the
derived-relations reference.
Deprecated entities:
MATCH (ax:N {kind: 'AnnotationAssertion'})
-[:E {role: 'property'}]->(:N {iri: 'http://www.w3.org/2002/07/owl#deprecated'}),
(ax)-[:E {role: 'subject'}]->(subj:N),
(ax)-[:E {role: 'value'}]->(val:N)
WHERE val.text = 'true'
RETURN subj.text AS deprecated_entity
ORDER BY deprecated_entity
SPARQL comparison¶
Ontopoiesis's Cypher surface queries the projection graph directly rather than RDF triples. The comparison below shows the same structural question in both models.
Named subclass relationships¶
SELECT ?subClass ?superClass
WHERE {
?subClass rdfs:subClassOf ?superClass .
FILTER(isIRI(?subClass) && isIRI(?superClass))
}
MATCH (ax:N {kind: 'SubClassOf'})
-[:E {role: 'sub'}]->(sub:N {kind: 'Class'}),
(ax)-[:E {role: 'super'}]->(sup:N {kind: 'Class'})
WHERE sub.iri IS NOT NULL AND sup.iri IS NOT NULL
RETURN sub.iri AS subclass, sup.iri AS superclass
ORDER BY subclass
Existential restrictions¶
SELECT ?class ?property ?filler
WHERE {
?class rdfs:subClassOf ?restriction .
?restriction a owl:Restriction ;
owl:onProperty ?property ;
owl:someValuesFrom ?filler .
}
MATCH (ax:N {kind: 'SubClassOf'})
-[:E {role: 'sub'}]->(cls:N {kind: 'Class'}),
(ax)-[:E {role: 'super'}]->(restriction:N {kind: 'ObjectSomeValuesFrom'})
-[:E {role: 'property'}]->(prop:N),
(restriction)-[:E {role: 'filler'}]->(filler:N)
WHERE cls.iri IS NOT NULL AND prop.iri IS NOT NULL
RETURN cls.iri AS class, prop.iri AS property,
COALESCE(filler.iri, filler.kind) AS filler
ORDER BY class, property
Property chains¶
SELECT ?property ?step ?position
WHERE {
?property owl:propertyChainAxiom ?list .
-- then walk rdf:first / rdf:rest by hand
}
MATCH (ax:N {kind: 'SubObjectPropertyOf'})
-[:E {role: 'super'}]->(sup:N),
(ax)-[:E {role: 'sub'}]->(:N {kind: 'ObjectPropertyChain'})
-[link:E {role: 'operand'}]->(step:N)
WHERE sup.iri IS NOT NULL AND step.iri IS NOT NULL
RETURN sup.iri AS property, step.iri AS chain_step, link.position AS position
ORDER BY property, position
N-ary axioms¶
SELECT ?axiom ?class
WHERE {
?axiom a owl:AllDisjointClasses ;
owl:members ?list .
?list rdf:rest*/rdf:first ?class .
FILTER(isIRI(?class))
}
ORDER BY ?axiom ?class
MATCH (ax:N {kind: 'DisjointClasses'})
-[:E {role: 'operand'}]->(cls:N)
WHERE cls.iri IS NOT NULL
RETURN ax.uid AS axiom, cls.iri AS class
ORDER BY axiom, class
Multi-hop structural questions¶
SELECT DISTINCT ?class ?superClass ?property ?filler
WHERE {
?class rdfs:subClassOf ?superClass .
FILTER(isIRI(?class) && isIRI(?superClass))
?class rdfs:subClassOf ?restriction .
?restriction a owl:Restriction ;
owl:onProperty ?property ;
owl:someValuesFrom ?filler .
}
ORDER BY ?class ?superClass ?property
MATCH (subAx:N {kind: 'SubClassOf'})
-[:E {role: 'sub'}]->(cls:N {kind: 'Class'}),
(subAx)-[:E {role: 'super'}]->(sup:N {kind: 'Class'}),
(restrictionAx:N {kind: 'SubClassOf'})
-[:E {role: 'sub'}]->(cls),
(restrictionAx)-[:E {role: 'super'}]->(restriction:N {kind: 'ObjectSomeValuesFrom'})
-[:E {role: 'property'}]->(prop:N),
(restriction)-[:E {role: 'filler'}]->(filler:N)
WHERE cls.iri IS NOT NULL
AND sup.iri IS NOT NULL
AND prop.iri IS NOT NULL
RETURN cls.iri AS class,
sup.iri AS superclass,
prop.iri AS property,
COALESCE(filler.iri, filler.kind) AS filler
ORDER BY class, superclass, property
Troubleshooting¶
Query returns no rows when rows are expected
The most common cause is a kind string mismatch. Kind strings must exactly match the
OWL 2 structural specification names as used in the projection — for example,
SubClassOf not subClassOf or subclass_of. Run the discovery query first to see
the exact kind strings present in your projection:
If the kind is present but the query still returns nothing, check whether the ontology
uses the pattern you expect. If all superclass expressions are anonymous intersections
or restrictions rather than named classes, a query for named-class-to-named-class
SubClassOf axioms will return no rows.
Query returns rows but iri is null
Anonymous constructs — axioms, class expressions, property expressions — have a uid
but no iri. Only named entities (Class, ObjectProperty, NamedIndividual, and so
on) carry an iri property. Add a WHERE n.iri IS NOT NULL clause to filter to named
entities, or use n.uid to identify anonymous nodes.
ontopoiesis query exits with a non-zero status
A syntax error in the Cypher string causes the command to exit non-zero and print the
error from the query engine. The most common source is unescaped quotes in an inline
-q string. Use a .cypher file with --file instead of -q for multi-line queries.
Projection file not found or appears empty
Run ontopoiesis build first to produce the .lbug file. If the file exists but queries
return nothing, the build may have failed partway through — rebuild with
ontopoiesis build --force to overwrite the existing projection.