RDF Triples: Subject, Predicate, Object Explained

An RDF triple is a statement made of three parts, a subject, a predicate, and an object, that asserts one fact: the subject has a relationship (the predicate) to the object. “The Eiffel Tower is located in Paris” is one triple. A set of triples is an RDF graph, and every RDF-based knowledge graph, from Wikidata to the schema.org markup on a web page, is a collection of them.

The triple as the atomic statement

RDF (Resource Description Framework) is the W3C’s data model for the semantic web, and the triple is its only unit. There are no tables, columns, or nested records. Anything more complex than one fact is expressed as several triples that share nodes. The three positions have distinct rules about what may fill them.

Subject: the thing the statement is about. It must be an IRI (an internationalized URI, such as http://www.wikidata.org/entity/Q243) or a blank node (an anonymous node with no global identifier, used for things that need not be named).

Predicate: the relationship or property. It must be an IRI, drawn from a vocabulary: rdf:type, rdfs:label, schema:location. Because predicates are IRIs, they can themselves be subjects of other triples that describe them.

Object: the value. It may be an IRI, a blank node, or a literal. A literal is a concrete value such as a string, a number, or a date. Literals carry either a datatype IRI ("330"^^xsd:decimal, "1889-03-31"^^xsd:date) or, for plain text, a language tag ("Eiffel Tower"@en). A literal with neither is treated as xsd:string.

Literals can only be objects because a literal is a value, not a thing that can have properties of its own. If a value needs to be described further, it becomes a node.

How triples form a graph

Each triple is a directed edge: the subject is the source node, the predicate is the edge label, and the object is the target node. When one triple’s object is another triple’s subject, the edges connect.

Eiffel Tower --located in--> Paris --country--> France
     |
     +--height--> 330 (xsd:decimal)
     |
     +--label--> "Eiffel Tower"@en

Nothing in RDF marks where one “record” ends and another begins; the graph is the union of all triples. This is what makes merging RDF from two sources trivial: because both use the same IRI for Paris, their triples about Paris attach to the same node when the sets are combined. Merging across sites is the subject of linked data.

Prefixes and Turtle syntax

Full IRIs are long. Turtle (Terse RDF Triple Language) is the most readable RDF serialization, and it introduces prefixes so that http://www.w3.org/2000/01/rdf-schema#label can be written rdfs:label. A Turtle document declares prefixes, then lists triples ending with periods. A semicolon repeats the subject and a comma repeats both subject and predicate, so several triples about one thing form a block.

Worked triples

The following Turtle states four facts about the Eiffel Tower and one about Paris, using Wikidata IRIs for the entities and schema.org for the properties.

@prefix rdf:    <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs:   <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd:    <http://www.w3.org/2001/XMLSchema#> .
@prefix schema: <https://schema.org/> .
@prefix wd:     <http://www.wikidata.org/entity/> .

wd:Q243 a schema:LandmarksOrHistoricalBuildings ;
        rdfs:label "Eiffel Tower"@en , "Tour Eiffel"@fr ;
        schema:location wd:Q90 ;
        schema:height "330"^^xsd:decimal .

wd:Q90  rdfs:label "Paris"@en .

Written out one per line, these are the six triples the block contains.

SubjectPredicateObjectObject kind
wd:Q243rdf:typeschema:LandmarksOrHistoricalBuildingsIRI
wd:Q243rdfs:label"Eiffel Tower"@enLiteral, language-tagged
wd:Q243rdfs:label"Tour Eiffel"@frLiteral, language-tagged
wd:Q243schema:locationwd:Q90IRI
wd:Q243schema:height"330"^^xsd:decimalLiteral, typed
wd:Q90rdfs:label"Paris"@enLiteral, language-tagged

The keyword a is Turtle shorthand for rdf:type. The two labels are separate triples distinguished only by language tag, and a graph holds both without conflict. The height is a typed literal: "330" is the lexical form and xsd:decimal tells a consumer to treat it as a number, so a SPARQL query can filter on ?height > 300. Without the datatype it would be a string. (Strictly, schema.org expects height to be a QuantitativeValue or Distance; the plain decimal keeps the example short.)

The same triple in N-Triples, Turtle, and JSON-LD

RDF is a data model, not a file format. A conformant parser produces the same graph from any serialization. The location triple above, in three formats:

N-Triples (one full triple per line, no prefixes, used for large dumps and streaming):

<http://www.wikidata.org/entity/Q243> <https://schema.org/location> <http://www.wikidata.org/entity/Q90> .

Turtle (prefixed, human-readable):

@prefix schema: <https://schema.org/> .
@prefix wd:     <http://www.wikidata.org/entity/> .

wd:Q243 schema:location wd:Q90 .

JSON-LD (JSON with a context; the format used on web pages):

{
  "@context": "https://schema.org",
  "@id": "http://www.wikidata.org/entity/Q243",
  "location": { "@id": "http://www.wikidata.org/entity/Q90" }
}

In JSON-LD, @id on the outer object supplies the subject, each key is a predicate expanded via the @context, and a nested object with only @id is an IRI object rather than a literal. Other serializations include RDF/XML, RDFa (attributes in HTML), and TriG. See JSON-LD vs Microdata vs RDFa for web publishing comparisons.

Quads and named graphs

A plain triple says nothing about its origin. RDF 1.1 datasets group triples into named graphs, each identified by an IRI; a triple plus its graph name is a quad. Named graphs let a triple store track provenance (these triples came from Wikidata; those from an internal CRM), apply access control, or delete a source as a unit. N-Quads and TriG carry the fourth element, and SPARQL restricts matching to a graph with the GRAPH keyword.

RDF-star: statements about statements

Plain RDF cannot easily annotate a triple. Saying when the Eiffel Tower’s height was recorded requires either reification (four extra triples describing the original one) or a blank node standing for the measurement. RDF-star (also written RDF*) allows a triple to appear as the subject or object of another triple:

<< wd:Q243 schema:height "330"^^xsd:decimal >> schema:dateCreated "2022-01-01"^^xsd:date .

RDF-star and SPARQL-star began as a community proposal and the W3C RDF-star Working Group is incorporating them into RDF 1.2 and SPARQL 1.2; GraphDB, Stardog, Oxigraph, and Apache Jena already support them. RDF-star is the closest RDF equivalent to properties on edges in a labeled property graph (LPG).

Triple stores as the storage layer

A triple store (or RDF store, or quad store when it supports named graphs) is a database built to hold and query triples. It indexes the positions in several orders so that any pattern, such as “all triples with this predicate,” can be answered quickly. The query language is SPARQL. Widely used stores include Apache Jena, Eclipse RDF4J, Ontotext GraphDB, Stardog, Blazegraph (which runs the Wikidata Query Service), Virtuoso (which runs DBpedia), Amazon Neptune, and Oxigraph. How they compare to property-graph databases such as Neo4j is covered in graph databases and knowledge graph vs graph database.

Schema.org JSON-LD is a set of triples

Every JSON-LD block on a web page is a compact way of writing triples. The following Organization markup with three properties is typical of what an SEO would add to a home page.

{
  "@context": "https://schema.org",
  "@type": "Organization",
  "@id": "https://example.com/#org",
  "name": "Example Corp",
  "url": "https://example.com/",
  "sameAs": "https://www.wikidata.org/wiki/Q12345"
}

A JSON-LD processor expands it to exactly four triples:

SubjectPredicateObject
<https://example.com/#org>rdf:type<https://schema.org/Organization>
<https://example.com/#org><https://schema.org/name>"Example Corp"
<https://example.com/#org><https://schema.org/url><https://example.com/>
<https://example.com/#org><https://schema.org/sameAs><https://www.wikidata.org/wiki/Q12345>

@type becomes an rdf:type triple and @id supplies the subject for all four. name is a string literal. url and sameAs are declared in the schema.org context as IRI-valued, so their values become IRI objects rather than strings. If @id were omitted, the subject would be a blank node, and nothing on another page could refer to the same organization.

For developers

Three points recur in practice. Choose or reuse IRIs deliberately; an entity with a stable IRI can be linked to from anywhere, and one described only by blank nodes cannot. Type every literal that is not free text (xsd:date, xsd:decimal, xsd:integer, xsd:boolean); untyped numbers are strings and will not sort or compare correctly. Use language tags on labels from the start, because retrofitting them across a large graph is tedious.

In Python, rdflib represents a triple as a tuple of URIRef, BNode, and Literal objects:

from rdflib import Graph, URIRef, Literal, Namespace, RDFS
from rdflib.namespace import XSD

SCHEMA = Namespace("https://schema.org/")
WD = Namespace("http://www.wikidata.org/entity/")

g = Graph()
g.add((WD.Q243, RDFS.label, Literal("Eiffel Tower", lang="en")))
g.add((WD.Q243, SCHEMA.location, WD.Q90))
g.add((WD.Q243, SCHEMA.height, Literal("330", datatype=XSD.decimal)))

print(g.serialize(format="turtle"))

For a fuller walkthrough of building and querying a graph, see knowledge graph in Python and the RDF reference.

For SEOs

Search engines read JSON-LD as triples and merge them into what they already know. Two consequences follow. First, IRIs carry identity, not names. Two pages that both say "name": "Example Corp" without a shared @id produce two anonymous subjects that a parser has no reason to treat as the same organization. Giving every mention the same @id (and pointing sameAs to the same Wikidata Q-ID) collapses them into one node; see Organization schema and sameAs schema.

Second, a property’s value must be the right kind of node. sameAs expects an IRI; address expects a PostalAddress node with its own triples, not a string. Validation tools such as the Rich Results Test report these as warnings, and each warning is a malformed triple. See structured data and entity SEO.

Common misconceptions

“A triple is a row with three columns.” Rows are independent; triples share nodes. The graph is the point, and it exists only because IRIs are reused across triples.

“Literals can be subjects.” They cannot. To say something about a value, promote it to a node.

“Blank nodes are a bug.” Blank nodes are correct for things with no identity outside their context, such as a postal address. They become a problem only when used for things that should be linkable.

Related pages

FAQ

What is a triple in RDF?

A triple is a single statement of the form subject, predicate, object, asserting that the subject has the named relationship to the object. “Eiffel Tower, located in, Paris” is one triple. The subject and predicate are IRIs (the subject may also be a blank node); the object is an IRI, a blank node, or a literal value such as a string, number, or date.

What is the difference between a triple and a semantic triple?

There is no difference in practice. “Semantic triple” is the general term for any subject-predicate-object statement; “RDF triple” is the same structure as defined by the W3C’s RDF standard, with specific rules about IRIs, blank nodes, literals, datatypes, and language tags. Knowledge graph literature uses the terms interchangeably.

What is a triple store?

A triple store is a database designed to store RDF triples (or quads, when named graphs are supported) and answer SPARQL queries over them. Examples include Apache Jena, GraphDB, Stardog, Blazegraph, Virtuoso, and Amazon Neptune. It indexes the subject, predicate, and object positions so that any pattern of known and unknown parts can be matched efficiently.

Is schema.org JSON-LD made of triples?

Yes. JSON-LD is a W3C serialization of RDF. When a processor expands a JSON-LD block, @id becomes the subject, each property key becomes a predicate IRI, and each value becomes an IRI, a nested (blank) node, or a literal object. A three-property Organization block expands to four triples, one of them the rdf:type statement from @type.

Sources and further reading

  • RDF 1.1 Concepts and Abstract Syntax (W3C Recommendation): https://www.w3.org/TR/rdf11-concepts/
  • RDF 1.1 Primer (W3C): https://www.w3.org/TR/rdf11-primer/
  • RDF 1.1 Turtle (W3C Recommendation): https://www.w3.org/TR/turtle/
  • RDF 1.1 N-Triples (W3C Recommendation): https://www.w3.org/TR/n-triples/
  • JSON-LD 1.1 (W3C Recommendation, 2020): https://www.w3.org/TR/json-ld11/
  • RDF-star Working Group (W3C): https://www.w3.org/groups/wg/rdf-star/
  • rdflib documentation: https://rdflib.readthedocs.io/