Repository navigation
Semantic_Knowledge_Graph_Validation_Starter_Pack
Michael DeBellis edited this page Mar 18, 2026
·
2 revisions
This document defines a practical validation architecture for Semantic Knowledge Graph (SKG) development using:
- OWL for semantics and inference
- SHACL for conformance and validation
- SPARQL for diagnostics and auditing
This approach is designed for real-world engineering workflows, balancing rigor, usability, and interoperability.
Use OWL for:
- Class hierarchies
- Property hierarchies
- Domain and range (when semantically justified)
owl:inverseOf- Property characteristics (transitive, symmetric, functional)
- Disjointness
- Logical restrictions
Guideline: Use OWL to represent what is true about the domain, not what is merely desirable in data.
Use SHACL for:
- Required properties
- Cardinality constraints
- Datatype validation
- Structural expectations
- Data quality rules
- Warning vs. violation severity
Guideline: Use SHACL to enforce what data should look like in your system.
Use SPARQL for:
- Debugging
- Data inspection
- Detecting anomalies
- Ontology hygiene checks
- Cross-cutting analysis
- Portable validation
Guideline: Use SPARQL to find what looks wrong or suspicious.
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix dcat: <http://www.w3.org/ns/dcat#> .
@prefix prov: <http://www.w3.org/ns/prov#> .
@prefix dp: <https://www.michaeldebellis.com/dp/> .
@prefix sf: <https://www.michaeldebellis.com/sf/> .
# A. Class Metadata Shape
dp:Class_Metadata_Shape
a sh:NodeShape ;
sh:targetClass owl:Class ;
sh:property [
sh:path rdfs:label ;
sh:minCount 1 ;
sh:severity sh:Warning ;
sh:message "Each class should have an rdfs:label."@en ;
] ;
sh:property [
sh:path skos:definition ;
sh:minCount 1 ;
sh:severity sh:Warning ;
sh:message "Each class should have a skos:definition."@en ;
] .
# B. Property Metadata Shape
dp:Property_Metadata_Shape
a sh:NodeShape ;
sh:targetClass owl:ObjectProperty ;
sh:property [
sh:path rdfs:label ;
sh:minCount 1 ;
sh:severity sh:Warning ;
] ;
sh:property [
sh:path skos:definition ;
sh:minCount 1 ;
sh:severity sh:Warning ;
] .
# (Repeat for DatatypeProperty and AnnotationProperty if needed)
# C. Dataset Must Have Label
dp:Dataset_Label_Shape
a sh:NodeShape ;
sh:targetClass dcat:Dataset ;
sh:property [
sh:path rdfs:label ;
sh:minCount 1 ;
sh:severity sh:Violation ;
] .
# D. Dataset Should Have Distribution
dp:Dataset_Distribution_Shape
a sh:NodeShape ;
sh:targetClass dcat:Dataset ;
sh:property [
sh:path dcat:distribution ;
sh:minCount 1 ;
sh:severity sh:Warning ;
] .
# E. Integer Datatype Example
dp:Row_Count_Shape
a sh:NodeShape ;
sh:targetSubjectsOf dp:row_count ;
sh:property [
sh:path dp:row_count ;
sh:datatype xsd:integer ;
sh:maxCount 1 ;
sh:severity sh:Violation ;
] .
# F. DateTime Datatype Example
dp:Created_At_Shape
a sh:NodeShape ;
sh:targetSubjectsOf dp:created_at ;
sh:property [
sh:path dp:created_at ;
sh:datatype xsd:dateTime ;
sh:severity sh:Violation ;
] .
# G. URI Datatype Example
dp:Access_URL_Shape
a sh:NodeShape ;
sh:targetSubjectsOf dp:access_url ;
sh:property [
sh:path dp:access_url ;
sh:datatype xsd:anyURI ;
sh:severity sh:Violation ;
] .
# H. Object Properties Should Have Inverses
dp:Object_Property_Inverse_Shape
a sh:NodeShape ;
sh:targetClass owl:ObjectProperty ;
sh:property [
sh:path owl:inverseOf ;
sh:minCount 1 ;
sh:severity sh:Warning ;
] .
# I. Activity Must Have Associated Agent
dp:Activity_Association_Shape
a sh:NodeShape ;
sh:targetClass prov:Activity ;
sh:property [
sh:path prov:wasAssociatedWith ;
sh:minCount 1 ;
sh:severity sh:Warning ;
] .
# 3. SPARQL Audit Pack
# A. Undeclared Properties
SELECT DISTINCT ?p
WHERE {
?s ?p ?o .
FILTER(isIRI(?p))
FILTER NOT EXISTS { ?p a owl:ObjectProperty }
FILTER NOT EXISTS { ?p a owl:DatatypeProperty }
FILTER NOT EXISTS { ?p a owl:AnnotationProperty }
}
ORDER BY ?p
# B. Undeclared Classes
SELECT DISTINCT ?class
WHERE {
?x a ?class .
FILTER(isIRI(?class))
FILTER NOT EXISTS { ?class a owl:Class }
}
ORDER BY ?class
# C. Classes Missing Labels
SELECT ?class
WHERE {
?class a owl:Class .
FILTER NOT EXISTS { ?class rdfs:label ?label }}
# D. Classes Missing Definitions
SELECT ?class
WHERE {
?class a owl:Class .
FILTER NOT EXISTS { ?class skos:definition ?def }}
# E. Properties Missing Definitions
SELECT ?property
WHERE {
?property a ?type .
FILTER(?type IN (owl:ObjectProperty, owl:DatatypeProperty))
FILTER NOT EXISTS { ?property skos:definition ?def }
}
# F. Object Properties Missing Inverses
SELECT ?property
WHERE {
?property a owl:ObjectProperty .
FILTER NOT EXISTS { ?property owl:inverseOf ?inv }
}
# G. Suspicious Annotation Property Usage
SELECT DISTINCT ?p
WHERE {
?s ?p ?o .
?p a owl:AnnotationProperty .
FILTER(isIRI(?o))
}
# H. Duplicate Labels
SELECT ?label (COUNT(?x) AS ?count)
WHERE {
?x rdfs:label ?label .
}
GROUP BY ?label
HAVING (COUNT(?x) > 1)
# I. Object Property Naming Violations
SELECT ?property
WHERE {
?property a owl:ObjectProperty .
BIND(REPLACE(STR(?property), '^.*[/#]', '') AS ?name)
FILTER(!STRSTARTS(?name, "has_") && !STRSTARTS(?name, "is_"))
}
# J. Datatype Properties Using "has_"
SELECT ?property
WHERE {
?property a owl:DatatypeProperty .
BIND(REPLACE(STR(?property), '^.*[/#]', '') AS ?name)
FILTER(STRSTARTS(?name, "has_"))
}```
# K. Entities Missing rdf:type
SELECT DISTINCT ?x
WHERE {
?x ?p ?o .
FILTER(isIRI(?x))
FILTER NOT EXISTS { ?x a ?t }}- undeclared properties
- naming issues
- duplicates
- required metadata
- datatype checks
- cardinality
- SHACL (conformance)
- SPARQL (hygiene)
- permissive
- warnings instead of violations
- inverses required
- tolerant of external data
- relaxed string/language constraints
- strict validation
- all metadata required
- no undeclared terms
- OWL for truth
- SHACL for quality gates
- SPARQL for investigation
Prefer flexibility over strict langString enforcement
Use SHACL (not OWL) for datatype rigor
Allow variation for integration scenarios
Enforce stricter rules only where needed