Primary reading
DuCharme — Ch 5–6
Chapters 5 and 6 cover SPARQL Update and applications. DuCharme's examples are practical and grounded — the closest thing to a cookbook for the patterns in this workbook.
INSERT DATA, DELETE WHERE, CONSTRUCT-into-graph, and the transactional reality of SPARQL Update. Five hands-on update operations — with a data safety mindset throughout.
SPARQL 1.1 defines a companion language — SPARQL Update — for writing to a graph store. It shares the same PREFIX syntax and the same graph pattern matching as SELECT queries, but the output is mutations to the store rather than a result set. The UPDATE endpoint is separate from the query endpoint by convention (Fuseki uses /update vs /query).
SPARQL Update is the standard way to manage the lifecycle of data in a triplestore: loading initial datasets, adding provenance annotations, correcting errors, materializing inferred triples, retiring outdated assertions. Every production knowledge graph system uses it. The queries in this workbook run against the /update endpoint in the Fuseki UI's "Update" tab.
Unlike SELECT queries, UPDATE operations permanently modify the store. Before running any update in this workbook, either: (a) work in a separate Fuseki dataset you don't mind destroying, or (b) have a backup copy of your TTL file to reload from. The Fuseki UI's "Upload files" function is your restore path. Every update operation below notes what it changes and how to undo it.
Load modules/02-modeling/artifacts/naruto-ontology/naruto-ontology-starter.ttl into a Fuseki dataset (call it naruto-update or similar — keep it separate from your main dataset). The update lab adds, modifies, and removes data from this dataset. Run each update in the "Update" tab of the Fuseki UI, not the Query tab.
SPARQL Update divides into two strategies: explicit (you specify exactly what to add or remove) and pattern-based (the store finds matches and acts on them).
| Operation | Strategy | What it does |
|---|---|---|
INSERT DATA | Explicit | Adds specific, hardcoded triples. No variables. Safest form — no unintended matches possible. |
DELETE DATA | Explicit | Removes specific, hardcoded triples. If the triple is not present, the operation silently succeeds (no error). |
INSERT WHERE | Pattern-based | Adds triples derived from a WHERE clause match. Powerful — can insert many triples from one operation. |
DELETE WHERE | Pattern-based | Finds and removes triples matching a pattern. Destructive — test the WHERE clause as a SELECT first. |
DELETE … INSERT … WHERE | Pattern-based | Replaces matched triples atomically (at graph level). The standard "update a value" pattern. |
CLEAR / DROP | Explicit | Removes all triples from a named graph (CLEAR) or removes the graph itself (DROP). Use carefully. |
COPY / MOVE | Explicit | Copies or moves graph contents between named graphs. Useful for version snapshotting. |
LOAD | Explicit | Loads an RDF file from a URL into a named graph. Convenient for batch loading. |
The most important compound operation. It atomically replaces the old value of a property with a new value — the SPARQL equivalent of SQL's UPDATE SET WHERE:
# Replace Naruto's rank from Genin to Jonin PREFIX naruto: <https://sensemaking-ai.com/ns/naruto#> PREFIX skos: <http://www.w3.org/2004/02/skos/core#> DELETE { naruto:NarutoUzumaki naruto:hasRank naruto:Genin . } INSERT { naruto:NarutoUzumaki naruto:hasRank naruto:Jonin . } WHERE { naruto:NarutoUzumaki naruto:hasRank naruto:Genin . }
The WHERE clause guards the operation: if Naruto is not currently Genin, neither the DELETE nor the INSERT fires. This is the safe pattern for rank promotions — it will not create a second hasRank triple if one already exists with the new value, because the guard fails if the old value is absent.
SPARQL Update is not transactional in the SQL sense. The Module 4 README's pain point: "most triplestores offer ACID at graph or statement level, but cross-graph multi-statement transactions are inconsistently supported."
What this means in practice:
# Chain two updates in one request (Fuseki executes both atomically) PREFIX naruto: <https://sensemaking-ai.com/ns/naruto#> PREFIX schema: <https://schema.org/> # First: snapshot the current state COPY GRAPH naruto:Ontology TO GRAPH naruto:OntologyBackup ; # Second: add new data INSERT DATA { GRAPH naruto:Ontology { naruto:JiraiyaSannin naruto:senseiOf naruto:NarutoUzumaki . } }
Fuseki supports full SPARQL 1.1 Update with Jena's ACID transactions at the dataset level. Oxigraph (the simpler Rust triplestore recommended in Exercise 4.1) offers ACID transactions per operation but has fewer extensions. For the purposes of this curriculum, both behave the same for the operations in this workbook. For production systems handling concurrent writes, check your triplestore's specific transaction documentation before designing the update pattern.
These operations run against the Naruto ontology starter data loaded into a test Fuseki dataset. Run them in order — each one builds on the previous state. After each operation, run a SELECT query to verify the change took effect before proceeding.
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> PREFIX schema: <https://schema.org/> PREFIX naruto: <https://sensemaking-ai.com/ns/naruto#> INSERT DATA { naruto:JiraiyaSannin a naruto:Ninja ; naruto:canonicalName "Jiraiya" ; schema:name "Jiraiya"@en , "自来也"@ja ; naruto:memberOfVillage naruto:VillageHiddenLeaf ; naruto:hasRank naruto:Jonin ; naruto:senseiOf naruto:NarutoUzumaki . }
PREFIX naruto: <https://sensemaking-ai.com/ns/naruto#> # Run this SELECT first to confirm the current state: # SELECT ?rank WHERE { naruto:NarutoUzumaki naruto:hasRank ?rank . } DELETE { naruto:NarutoUzumaki naruto:hasRank naruto:Genin . } INSERT { naruto:NarutoUzumaki naruto:hasRank naruto:Jonin . } WHERE { naruto:NarutoUzumaki naruto:hasRank naruto:Genin . }
PREFIX naruto: <https://sensemaking-ai.com/ns/naruto#> # INSERT WHERE: for every senseiOf triple, # add the inverse studentOf triple if it doesn't already exist. INSERT { ?student naruto:studentOf ?sensei . } WHERE { ?sensei naruto:senseiOf ?student . FILTER NOT EXISTS { ?student naruto:studentOf ?sensei . } }
PREFIX schema: <https://schema.org/> PREFIX naruto: <https://sensemaking-ai.com/ns/naruto#> # Create a named graph containing only characters # who appear in the Chunin Exams arc. INSERT { GRAPH naruto:ChunexamsCharacters { ?ninja a naruto:Ninja ; naruto:canonicalName ?name ; naruto:appearsInArc naruto:ChunexamsArc . } } WHERE { ?ninja a naruto:Ninja ; naruto:canonicalName ?name ; naruto:appearsInArc naruto:ChunexamsArc . }
PREFIX naruto: <https://sensemaking-ai.com/ns/naruto#> # Step 1: Snapshot the default graph into a backup named graph COPY DEFAULT TO GRAPH naruto:SnapshotBeforeBulkUpdate ; # Step 2: Verify the snapshot exists before proceeding # (Run separately as a SELECT to check triple count matches) # Step 3 (run separately after verifying): clear and reload from file # CLEAR DEFAULT ; # LOAD <file:///path/to/naruto-ontology-starter.ttl> ;
Chapters 5 and 6 cover SPARQL Update and applications. DuCharme's examples are practical and grounded — the closest thing to a cookbook for the patterns in this workbook.
Section 3 covers the full update language syntax. Section 4 covers the update protocol (HTTP). Bookmark it — you will need it when a compound operation behaves unexpectedly.
The Fuseki documentation covers the /update endpoint, the dataset configuration, and transaction semantics specific to Jena's implementation. Read the "SPARQL Update" section before Exercise 4.1.
The SERVICE keyword, federation failure modes, triplestore options, and the EC2 deployment guide for Exercise 4.1. The deployment work feeds directly into the capstone.
The base data file for this workbook's update lab. Load into a separate Fuseki test dataset before running any update operations. Keep the original TTL file as your restore point.
All eight update operations, the DELETE … INSERT … WHERE pattern, the backup-restore workflow, and transactional gotchas — one page. Available when Module 4 materials are complete.