RDF Basics

A ten-minute introduction to the data model Waratah stores and queries. Nothing here is Waratah-specific — it is RDF 1.1, the model shared by every RDF system, so it transfers to any tool in this space.

Statements, not tables

RDF keeps data as simple three-part statements called triples:

⟨subject⟩  ⟨predicate⟩  ⟨object⟩

Read a triple as one sentence about one thing:

⟨http://ex/alice⟩  ⟨http://ex/livesIn⟩  ⟨http://ex/brisbane⟩
"Alice lives in Brisbane."

Every fact gets its own triple, and triples that share a subject or an object are connected — that is the graph in graph database. Nothing is fixed in advance about which predicates exist or which subjects carry them; adding a new kind of fact never changes the shape of what is already stored, and data from two different sources merges whenever they use the same identifiers.

IRIs

Subjects and predicates are IRIs — globally unique identifiers that look like URLs (http://ex/alice). An IRI identifies a thing; it does not have to be fetchable. Because IRIs are long, every syntax lets you abbreviate them with a prefix:

PREFIX ex: <http://ex/>
ex:alice   # same as <http://ex/alice>

Predicates come from vocabularies — shared IRI sets that give a community common words. rdf:type ("is a"), rdfs:label ("is named"), and the xsd: datatypes below are the everyday core.

Literals

The object of a triple can also be a literal — a value rather than an identifier:

"http://ex/name" → "Alice"
"2025"^^xsd:gYear
"Sunny"@en

A literal is a string, optionally with a datatype (2025 as a year, not a bare word) or a language tag (Sunny as English text). Datatypes come from the XML Schema namespace: xsd:string, xsd:integer, xsd:double, xsd:boolean, and — important for Waratah — xsd:dateTime, xsd:date, xsd:gYear, and xsd:gYearMonth.

Blank nodes

A triple’s subject or object can also be a blank node: an identifier that is local to the store, written _:b0 in serializations. Blank nodes say "some thing exists here, but it has no name of its own" — typically for structure that only makes sense inside its parent fact. You will rarely write them by hand.

Graphs: triples get a fourth part

RDF lets statements be grouped into named graphs, which adds a fourth slot — where the statement lives — making each fact a quad:

⟨subject⟩  ⟨predicate⟩  ⟨object⟩  ⟨graph⟩

Triples you load without saying otherwise land in the default graph. Named graphs are how one store holds many datasets (or many snapshots, or per-source data) side by side and queries can address them. This is why RDF stores like Waratah are called quadstores.

Turtle, the everyday syntax

Turtle is the compact text serialization you will load most often. The demo dataset from Getting Started, written as Turtle:

@prefix ex: <http://ex/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .

ex:alice rdf:type ex:Person ;
         ex:name "Alice" ;
         ex:livesIn ex:brisbane .

ex:bob rdf:type ex:Person ;
       ex:name "Bob" ;
       ex:livesIn ex:hobart .

ex:brisbane rdf:type ex:City ;
            ex:hasWeather "Sunny" .

ex:hobart rdf:type ex:City ;
          ex:hasWeather "Cold" .

The semicolons continue statements about the same subject; a is the usual shorthand for rdf:type. The same data comes in other shapes — N-Triples (one triple per line, no prefixes), N-Quads and TriG (the quad forms), RDF/XML, and gzipped variants of these; Waratah’s loader reads all of them.

What a query looks like

SPARQL is RDF’s query language, and its core idea is one line long: write the shape of the statements you want, with variables in the slots you do not know yet:

SELECT ?name WHERE {
  ?person ex:livesIn ex:brisbane .
  ?person ex:name ?name .
}

The store finds every way to fill the variables with real triples — here, every ?name belonging to someone who livesIn ex:brisbane. SPARQL Basics builds on this with filters, optionals, unions, and aggregates.