Semantic_Knowledge_Graph_Validation_Starter_Pack - mdebellis/SemanticKG-Design GitHub Wiki

Semantic Knowledge Graph Validation Starter Pack

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.


1. Validation Architecture Overview

OWL → Semantic Meaning and Inference

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.


SHACL → Conformance and Engineering Rules

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.


SPARQL → Diagnostics and Auditing

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.


2. SHACL Starter Pack

Prefixes

@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 }}

4. Recommended Workflow

During Development Run SPARQL:

  • undeclared properties
  • naming issues
  • duplicates

Before Merges / Snapshots Run SHACL:

  • required metadata
  • datatype checks
  • cardinality

Before Release / Sharing Run BOTH:

  • SHACL (conformance)
  • SPARQL (hygiene)

5. Profiles (Optional but Recommended)

Development Profile

  • permissive
  • warnings instead of violations
  • inverses required

Integration Profile

  • tolerant of external data
  • relaxed string/language constraints

Release Profile

  • strict validation
  • all metadata required
  • no undeclared terms

6. Guiding Principle

  • OWL for truth
  • SHACL for quality gates
  • SPARQL for investigation

7. Notes on Strings and Interoperability

Prefer flexibility over strict langString enforcement

Use SHACL (not OWL) for datatype rigor

Allow variation for integration scenarios

Enforce stricter rules only where needed