Sensemaking AI · Sensemaking Semantic Web
Submodule 1.2 · Foundations

SPARQL, deeper.

Five query patterns beyond the basics: DESCRIBE, UNION, property paths, FILTER NOT EXISTS, and VALUES — all on the Naruto dataset. Start Fuseki before you begin.

Module 1 · Weeks 1–3 Requires Fuseki + starter kit ~90 min hands-on DESCRIBE · UNION · paths · VALUES
Dataset Naruto Greek mythology
Checking for Fuseki at localhost:3030…

This picks up where 1.1 left off.

The five query patterns here — DESCRIBE, UNION, property paths, FILTER NOT EXISTS, VALUES — build on the SELECT, GROUP BY, ASK, OPTIONAL, and CONSTRUCT patterns in the 1.1 workbook. If those patterns still feel uncertain, work through the 1.1 workbook before continuing here.

The dataset is the same as the 1.1 workbook: data/example.ttl — eight ninja, three teams, two villages, several jutsu, sensei–student and rival relationships. The sensemaking: prefix is bound to https://sensemaking-ai.com/ns/example#. If you are not sure what data is in the file, open it in a text editor before running queries — prediction before execution is the habit.

Loading the Naruto data

From the starter-kit root: fuseki-server --config=fuseki/config.ttl. In the Fuseki UI, load data/example.ttl into the mythology dataset (that is the dataset name the starter kit creates — it serves both the Naruto and mythology workbooks depending on which file you load). All five queries below use the sensemaking: prefix bound to https://sensemaking-ai.com/ns/example#; they will not return results if the mythology domain data is loaded instead of data/example.ttl.

The ideas behind these queries.

If you've worked through the Sub-module 1.2 synthesis doc, skip ahead — this section condenses that material for quick reference. If you haven't, expand below before running the query lab.

Core SPARQL concepts — expand to review

The endpoint model

A SPARQL endpoint is an HTTP service: you POST a query, you get results back. Two endpoints in this curriculum:

  • Local Fuseki at localhost:3030 — your data, no rate limits, no internet required.
  • Wikidata at query.wikidata.org — one of the largest open knowledge graphs, read-only, rate-limited, with Wikidata-specific extensions (SERVICE wikibase:label).

Query anatomy

① PREFIX declarations — short aliases for full IRIs
PREFIX schema:      <https://schema.org/>
PREFIX sensemaking: <https://sensemaking-ai.com/ns/example#>

② SELECT clause — which variables to project
SELECT ?name ?teamName

③ WHERE clause — graph pattern that must match
WHERE {
  ?ninja a sensemaking:Ninja ;
         schema:name ?name ;
         sensemaking:memberOfTeam ?team .
  ?team schema:name ?teamName .
}

④ Solution modifiers — ORDER BY, LIMIT, GROUP BY
ORDER BY ?teamName ?name

The four query forms

FormReturnsUse when
SELECTTable of variable bindingsYou want a list of facts — the everyday form.
ASKtrue / falseYou only need to know whether a pattern exists.
CONSTRUCTA new RDF graphYou want to derive or transform triples.
DESCRIBEAll known facts about a URIYou're exploring an unknown resource.

Three things that surprise people

  • The LANG tag trap. Multilingual literals multiply rows without a FILTER. Add FILTER (LANG(?label) = "en") whenever data has language-tagged values.
  • OPTIONAL is a left join. A node with two jutsu appears twice in results. Use GROUP_CONCAT or restructure to collapse to one row.
  • Plain SPARQL sees only what's in the store. OWL property declarations (symmetric, inverse) have no effect without a reasoner. This becomes Module 2's core topic.

Full detail, query anatomy diagrams, and three live Wikidata queries: Sub-module 1.2 synthesis doc.

Read the file before running queries.

Three patterns in example.ttl that become relevant in this workbook's queries. You saw them in the 1.1 workbook too — but the queries here ask them in new ways.

# senseiOf: directed, not declared symmetric
sensemaking:KakashiHatake
    sensemaking:senseiOf
        sensemaking:NarutoUzumaki ,
        sensemaking:SasukeUchiha ,
        sensemaking:SakuraHaruno .

sensemaking:KurenaiYuhi
    sensemaking:senseiOf
        sensemaking:HinataHyuga .
senseiOf is one-directional. The file states who teaches whom, but does not also state who is a student of whom. Query q02 uses UNION to find both sensei and students in a single result. Query q03 uses a property path to chain senseiOf into a team lookup in a single step.
# hasJutsu: only some ninja have it
sensemaking:KakashiHatake
    sensemaking:hasJutsu
        sensemaking:Sharingan ,
        sensemaking:ShadowClone .

sensemaking:NarutoUzumaki
    sensemaking:hasJutsu
        sensemaking:ShadowClone .

# Sakura and Rock Lee: no hasJutsu triple
Absence is not negation. Sakura and Rock Lee have no hasJutsu triple. That does not mean they have no jutsu — it means this dataset does not assert any. Query q04 uses FILTER NOT EXISTS to find exactly these ninja. The open-world assumption distinction matters: the query finds "no jutsu asserted here," not "provably no jutsu."
# rivalOf: asserted one direction only
sensemaking:NarutoUzumaki
    sensemaking:rivalOf
        sensemaking:SasukeUchiha .

sensemaking:Gaara
    sensemaking:rivalOf
        sensemaking:RockLee .
rivalOf is declared symmetric (owl:SymmetricProperty) in the ontology, but plain SPARQL sees only what's in the store. The reverse direction — Sasuke rivals Naruto — is not asserted. Query q02's UNION includes rivals in one direction only. Challenge C3 asks you to use a path to find the reverse.

Five patterns, five queries.

Each query introduces one pattern not covered in the 1.1 workbook. Read the pattern description, predict the output, copy the query into Fuseki, then open the "Think about this" panel after running it.

q01
Tell me everything the dataset knows about Kakashi.
Pattern: DESCRIBE · all outgoing triples for a named resource
Open Fuseki ↗
PREFIX sensemaking: <https://sensemaking-ai.com/ns/example#>

DESCRIBE sensemaking:KakashiHatake
q02
Who plays a relational role — sensei OR rival of someone?
Pattern: UNION · merge two independent graph patterns · DISTINCT deduplication
Open Fuseki ↗
PREFIX schema:      <https://schema.org/>
PREFIX sensemaking: <https://sensemaking-ai.com/ns/example#>

SELECT DISTINCT ?name ?role WHERE {
  {
    ?ninja sensemaking:senseiOf ?student .
    ?ninja schema:name ?name .
    BIND("sensei" AS ?role)
  }
  UNION
  {
    ?ninja sensemaking:rivalOf ?other .
    ?ninja schema:name ?name .
    BIND("rival" AS ?role)
  }
}
ORDER BY ?role ?name
q03
Which sensei teaches students in which teams — in one step?
Pattern: property path · / (sequence) chains two predicates into one pattern
Open Fuseki ↗
PREFIX schema:      <https://schema.org/>
PREFIX sensemaking: <https://sensemaking-ai.com/ns/example#>

SELECT DISTINCT ?senseiName ?teamName WHERE {
  ?sensei schema:name ?senseiName ;
          sensemaking:senseiOf/sensemaking:memberOfTeam ?team .
  ?team schema:name ?teamName .
}
ORDER BY ?senseiName
q04
Which ninja have no jutsu listed in the dataset?
Pattern: FILTER NOT EXISTS · closed-world query on an open-world dataset
Open Fuseki ↗
PREFIX schema:      <https://schema.org/>
PREFIX sensemaking: <https://sensemaking-ai.com/ns/example#>

SELECT ?name WHERE {
  ?ninja a sensemaking:Ninja ;
         schema:name ?name .
  FILTER NOT EXISTS {
    ?ninja sensemaking:hasJutsu ?j .
  }
}
ORDER BY ?name
q05
Show me the village and team for these three specific ninja.
Pattern: VALUES · inline data · parameterized lookup with OPTIONAL
Open Fuseki ↗
PREFIX schema:      <https://schema.org/>
PREFIX sensemaking: <https://sensemaking-ai.com/ns/example#>

SELECT ?name ?villageName ?teamName WHERE {
  VALUES ?ninja {
    sensemaking:NarutoUzumaki
    sensemaking:SasukeUchiha
    sensemaking:Gaara
  }
  ?ninja schema:name ?name ;
         sensemaking:memberOfVillage ?village .
  ?village schema:name ?villageName .
  OPTIONAL {
    ?ninja sensemaking:memberOfTeam ?team .
    ?team schema:name ?teamName .
  }
}
ORDER BY ?name

Four things to build.

Each challenge extends or recombines patterns from the query lab. Write the query before opening the solution panel.

C1 Find all characters who are rivals of someone — in both directions

In the dataset, rivalOf is asserted one way: Naruto rivals Sasuke; Gaara rivals Rock Lee. But rivalry should be mutual. Use UNION to find all characters who appear on either side of a rivalOf triple. Return each character's name once (use DISTINCT).

Expected result and one approach

Expected: 4 rows — Gaara, Naruto Uzumaki, Rock Lee, Sasuke Uchiha. Rock Lee and Sasuke appear as objects of rivalOf triples, not subjects.

PREFIX schema:      <https://schema.org/>
PREFIX sensemaking: <https://sensemaking-ai.com/ns/example#>

SELECT DISTINCT ?name WHERE {
  {
    ?n sensemaking:rivalOf ?other .
    ?n schema:name ?name .
  }
  UNION
  {
    ?other sensemaking:rivalOf ?n .
    ?n schema:name ?name .
  }
}
ORDER BY ?name

This is why rivalOf being owl:SymmetricProperty matters: with a reasoner, you would not need the UNION — the engine would derive the reverse triples automatically. Without a reasoner, UNION is how you query in both directions at once.

C2 Use an inverse path to find all students of a given sensei

The ^ operator inverts a property path: ?student ^sensemaking:senseiOf ?sensei traverses senseiOf backwards. Rewrite q03 to start from a fixed sensei IRI and find all their students using ^sensemaking:senseiOf. Return student names only.

Expected result and one approach

Expected for Kakashi: 3 rows — Naruto Uzumaki, Sakura Haruno, Sasuke Uchiha.

PREFIX schema:      <https://schema.org/>
PREFIX sensemaking: <https://sensemaking-ai.com/ns/example#>

SELECT ?studentName WHERE {
  ?student ^sensemaking:senseiOf sensemaking:KakashiHatake ;
           schema:name ?studentName .
}
ORDER BY ?studentName

Equivalently: sensemaking:KakashiHatake sensemaking:senseiOf ?student — the inverse path is not strictly necessary here since the data has senseiOf asserted in the subject→object direction. But ^ is useful when you only have access to the object-side of a triple and want to "walk back."

C3 Find all jutsu that appear in the dataset, regardless of who has them

Write a SELECT that returns the label of every jutsu in the dataset — distinct values, sorted. Use skos:prefLabel if jutsu are typed as skos:Concept, or rdfs:label if they use that predicate. Check example.ttl to see how jutsu are modeled before writing the query.

Expected result and one approach

Expected: 4–5 rows — Byakugan, Sand Manipulation, Shadow Clone Jutsu, Sharingan (and any others in the file). The exact set depends on what's asserted in example.ttl.

PREFIX skos:        <http://www.w3.org/2004/02/skos/core#>
PREFIX sensemaking: <https://sensemaking-ai.com/ns/example#>

SELECT DISTINCT ?jutsuLabel WHERE {
  ?jutsu a skos:Concept ;
         skos:prefLabel ?jutsuLabel .
  FILTER (LANG(?jutsuLabel) = "en" || LANG(?jutsuLabel) = "")
}
ORDER BY ?jutsuLabel

The LANG filter handles both the case where labels have no language tag (LANG returns "") and where they have @en explicitly. Without it, multilingual labels would produce duplicate rows per jutsu.

C4 Combine UNION and FILTER NOT EXISTS

Find all ninja who are "involved" — either a sensei of someone, or on a team — but who have NO jutsu listed. This combines the UNION pattern from q02 with the FILTER NOT EXISTS pattern from q04. Return names sorted alphabetically.

Expected result and one approach

Expected: 2 rows — Kurenai Yuhi (sensei, no jutsu) and Rock Lee (Team Guy, no jutsu). Sakura has no jutsu but is also a team member — she should appear too. Verify against your dataset.

PREFIX schema:      <https://schema.org/>
PREFIX sensemaking: <https://sensemaking-ai.com/ns/example#>

SELECT DISTINCT ?name WHERE {
  ?ninja a sensemaking:Ninja ;
         schema:name ?name .
  {
    ?ninja sensemaking:senseiOf ?student .
  }
  UNION
  {
    ?ninja sensemaking:memberOfTeam ?team .
  }
  FILTER NOT EXISTS {
    ?ninja sensemaking:hasJutsu ?j .
  }
}
ORDER BY ?name

Note how FILTER NOT EXISTS operates on the full row from the outer WHERE block — it checks each matched ninja (from either UNION branch) for the absence of jutsu. The DISTINCT collapses duplicates from a ninja matching both branches.

Five good next reads.

Query reference

Learning SPARQL

DuCharme. The curriculum's canonical SPARQL reference. Chapters 3–4 cover property paths, aggregation, and CONSTRUCT in depth — the natural next step from this workbook.

Synthesis doc

Sub-module 1.2 synthesis

The reading companion for this workbook. Covers the four query forms conceptually and has three runnable Wikidata queries if you haven't tried the public endpoint yet.

Public endpoint

Wikidata Query Service

Apply the property path and UNION patterns here on a dataset with millions of nodes. The helper UI provides example queries — modify them rather than starting from scratch.

W3C spec

SPARQL 1.1 specification

Authoritative on FILTER NOT EXISTS vs MINUS (section 8.3), property paths (section 9), and VALUES (section 10.3). Read the relevant sections when something surprising happens.

Domain variant

Mythology workbook

Same five patterns applied to Greek mythology data. Deities, realms, powers, and championed relationships. If Naruto is familiar ground, the mythology domain forces you to read the data rather than rely on domain knowledge.

Module context

Module 1 README

The exercise list and primary project. The SPARQL patterns in this workbook map directly to the three queries Exercise 1.3 asks you to write against your own resume data.

Cheatsheet

Module 1 SPARQL quick-reference (coming soon)

Prefix block, query anatomy, all five query patterns from this workbook — one-page reference card. Available when Module 1 materials are complete.