I gave this tutorial at the 2023 Knowledge Graph Conference at Cornell University.
The tutorial included a demo showcasing how SPARQL UPDATE and named graphs can be used to create transactional workflows.
The demo works with a “superheroes.ttf” RDF file generated using ChatGPT for about forty heroes and villains from the DC and Marvel universes. A typical record looks as follows:
# Raven (Rachel Roth)
ex:Raven rdf:type ex:Superhero ;
rdfs:label "Raven" ;
ex:alterEgo "Rachel Roth" ;
ex:description "A half-demon, half-human sorceress and member of the Teen Titans who uses her dark magic and telepathy to fight against evil." ;
ex:superPowers "Dark magic, telepathy, telekinesis, and dimensional travel" ;
ex:gender "Female" ;
ex:universe "DCEU" ;
ex:appearance "Long dark hair, pale skin, dark hooded cloak, red gem on forehead" ;
ex:associatedWith ex:TeenTitans ;
ex:dndAlignment "True Neutral" ;
ex:myersBriggsType "INTP" .
The transformation is a SPARQL UPDATE script, run on Jena.
PREFIX ext: <http://mu.semte.ch/vocabularies/ext/>
PREFIX gr: <http://purl.org/goodrelations/v1#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix ex: <http://example.org/>
prefix cagleReport: <https://theCagleReport.com/ns/>
prefix graph: <https://theCagleReport.com/ns/graph#>
prefix sh: <http://www.w3.org/ns/shacl#>
prefix shext: <http://www.w3.org/ns/shacl-ext#>
prefix Character: <https://theCagleReport.com/ns/Character#>
prefix Author: <https://theCagleReport.com/ns/Author#>
prefix Gender: <https://theCagleReport.com/ns/Gender#>
prefix Org: <https://theCagleReport.com/ns/Org#>
prefix Universe: <https://theCagleReport.com/ns/Universe#>
prefix Entity: <https://theCagleReport.com/ns/Entity#>
prefix DNDAlignment: <https://theCagleReport.com/ns/DNDAlignment#>
prefix MyersBriggsType: <https://theCagleReport.com/ns/MyersBriggsType#>
prefix Message: <https://theCagleReport.com/ns/Message#>
prefix project: <file:///Users/kurtc/OneDrive/Documents/GitHub/rdfTransform/>
DROP GRAPH ex: ;
CREATE GRAPH ex: ;
LOAD project:superheroes.ttl INTO GRAPH ex: ;
#LOAD project:superheroesDelta.ttl INTO GRAPH ex: ;
DROP GRAPH graph:superheroes ;
CREATE GRAPH graph:superheroes ;
DELETE {
GRAPH graph:superheroes {
?newS Character:lastUpdated ?oldDate.
?newS ?pOld ?oOld.
}
}
INSERT {
GRAPH graph:superheroes {
?newS a Character: .
?newS rdfs:label ?label.
?newS Character:lastUpdated ?date .
?newS Character:type ?type .
?newS Character:alterEgo ?alterEgo .
?newS Character:description ?description .
?newS Character:superPowers ?superPowers .
?newS Character:gender ?gender .
?newS Character:universe ?universe .
?newS Character:appearance ?appearance .
?newS Character:associatedWith ?associatedWith .
?newS Character:memberOf ?org .
?newS Character:nemesis ?nemesis .
?newS Character:dndAlignment ?dndAlignment .
?newS Character:myersBriggsType ?myersBriggsType .
?dndAlignment a DNDAlignment:;
rdfs:label ?dndAlignmentStr;
.
?myersBriggsType a MyersBriggsType:;
rdfs:label ?myersBriggsTypeStr;
.
?gender a Gender:;
rdfs:label ?genderStr;
.
?universe a Universe:;
rdfs:label ?universeStr;
. }
}
WHERE {
GRAPH ex: {
?s a ?exclass.
bind(strafter(STR(?exclass),str(ex:)) as ?localName)
bind(?localName as ?prefix)
bind(concat(str(cagleReport:),?prefix,"#") as ?nsStr)
bind(iri(?nsStr) as ?ns)
bind(strafter(STR(?s),str(ex:)) as ?localSStr)
bind(concat(?nsStr,?localSStr) as ?newSStr)
bind(iri(?newSStr) as ?newS)
?s rdfs:label ?label.
?s a ?type ;
optional {?s ex:alterEgo ?alterEgo }
optional {?s ex:description ?description }
optional {?s ex:superPowers ?superPowers }
optional {?s ex:appearance ?appearance }
optional {?s ex:associatedWith ?associatedWithEx.
bind(iri(concat(str(Character:),strafter(str(?associatedWithEx),str(ex:)))) as ?associatedWith )
}
optional {?s ex:nemesis ?nemesisEx
bind(iri(concat(str(Character:),strafter(str(?nemesisEx),str(ex:)))) as ?nemesis )
}
optional {?s ex:memberOf ?orgEx
bind(iri(concat(str(Org:),strafter(str(?orgEx),str(ex:)))) as ?org )
}
optional {?s ex:dndAlignment ?dndAlignmentStr.
bind(iri(concat(str(DNDAlignment:),replace(?dndAlignmentStr,' ','_'))) as ?dndAlignment )
}
optional {?s ex:myersBriggsType ?myersBriggsTypeStr .
bind(iri(concat(str(MyersBriggsType:),replace(?myersBriggsTypeStr,' ','_'))) as ?myersBriggsType )
}
optional {?s ex:universe ?universeStr .
bind(iri(concat(str(Universe:),?universeStr)) as ?universe )
}
optional {?s ex:gender ?genderStr .
bind(iri(concat(str(Gender:),?genderStr)) as ?gender )
}
bind(NOW() as ?date)
}
optional {
graph graph:superheroes {
?newS Character:lastUpdated ?oldDate.
?newS ?pOld ?oOld.
}
}
};
DROP GRAPH graph:shacl;
CREATE GRAPH graph:shacl;
INSERT {
GRAPH graph:shacl {
?ns a sh:NodeShape, rdfs:Class ;
shext:namespace ?nsStr ;
shext:prefix ?prefix ;
shext:exclass ?exclass;
sh:targetClass ?ns ;
sh:property ?prop ;
.
?prop a sh:PropertyShape ;
sh:name ?localPropName ;
sh:path ?prop ;
sh:nodeKind ?nodeKind;
}
}
WHERE {
GRAPH ex: {
?s a ?exclass.
bind(strafter(STR(?exclass),str(ex:)) as ?localName)
bind(?localName as ?prefix)
bind(concat(str(cagleReport:),?prefix,"#") as ?nsStr)
bind(iri(?nsStr) as ?ns)
?s ?p ?o.
bind(strafter(STR(?p),str(ex:)) as ?localPropName)
bind(iri(concat(?nsStr,?localPropName)) as ?prop)
filter(!sameTerm(?prop,?ns))
bind(if(isIRI(?o),sh:IRI,if(isLiteral(?o),sh:Literal,sh:BlankNode)) as ?nodeKind)
}
};
INSERT {
GRAPH graph:Message {
?message a Message: ;
Message:hasDate ?date;
Message:hasBody ?body;
Message:hasAuthor ?author;
}
}
WHERE {
bind(NOW() as ?date)
bind(iri(concat(str(Message:),str(?date))) as ?message)
bind("New updates to Superheroes have just been made" as ?body)
bind(Author:DorothyWoolfolk as ?author)
}
The script, when run, uploads the file from a local file system using the LOAD command, then generates two graphs: Graph:Superheroes and Graph:SHACL. The Superheroes graph transforms the example content to an internal set of namespaces. For instance, the following is the entry for Raven, given above:
PREFIX ext: <http://mu.semte.ch/vocabularies/ext/>
PREFIX gr: <http://purl.org/goodrelations/v1#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix ex: <http://example.org/>
prefix cagleReport: <https://theCagleReport.com/ns/>
prefix graph: <https://theCagleReport.com/ns/graph#>
prefix sh: <http://www.w3.org/ns/shacl#>
prefix shext: <http://www.w3.org/ns/shacl-ext#>
prefix Character: <https://theCagleReport.com/ns/Character#>
prefix Author: <https://theCagleReport.com/ns/Author#>
prefix Gender: <https://theCagleReport.com/ns/Gender#>
prefix Org: <https://theCagleReport.com/ns/Org#>
prefix Universe: <https://theCagleReport.com/ns/Universe#>
prefix Entity: <https://theCagleReport.com/ns/Entity#>
prefix DNDAlignment: <https://theCagleReport.com/ns/DNDAlignment#>
prefix MyersBriggsType: <https://theCagleReport.com/ns/MyersBriggsType#>
prefix Message: <https://theCagleReport.com/ns/Message#>
Superhero:Raven
rdf:type Character: ;
rdfs:label "Raven" ;
Character:alterEgo "Rachel Roth" ;
Character:appearance
"Long dark hair, pale skin, dark hooded cloak, red gem on forehead" ;
Character:associatedWith
TeenTitans ;
Character:description
"A half-demon, half-human sorceress and member of the Teen Titans who uses her dark magic and telepathy to fight against evil." ;
Character:dndAlignment
DNDAlignment:True_Neutral ;
Character:gender
Gender:Female ;
Character:lastUpdated
"2023-05-08T01:13:30.06-07:00"^^xsd:dateTime ;
Character:memberOf Org:TeenTitans ;
Character:myersBriggsType
MyersBriggsType:INTP ;
Character:superPowers
"Dark magic, telepathy, telekinesis, and dimensional travel" ;
Character:type
ex:Superhero ;
Character:universe Universe:DCEU .
The SPARQL for generating the SHACL is straightforward enough that I leave it as an exercise to the reader.
Conclusion
More articles to come – this week has been spent fighting colds and focusing on contracts.
Kurt Cagle is the Editor in Chief of The Cagle Report, a former community editor for Data Science Central, and is the principal for Semantical LLC, as well as a regular contributing writer for Linked In. He has written twenty four books and hundreds of articleson programming and data interchange standards. He maintains a Calendly free consultation site at https://calendly.com/semantical – if you have a question, want to suggest a story, or just want to chat, set up a free consultation appointment with him there.
You must log in to post a comment.