RDF's power is that a predicate is a URI — globally identifiable. If two graphs use foaf:knows, they mean the same relationship. If you define your own :knows, you mean whatever you decide. Shared vocabularies are the convention layer that makes the first case work at scale.
Without shared vocabularies, every RDF graph is an island. With them, two organizations can independently describe a person using foaf:Person and the descriptions merge without configuration. A search engine encounters schema:name on a web page and knows what to do with it. A job seeker's resume links a skill to skos:exactMatch and the link resolves into a continent-wide occupational taxonomy. None of this works if every publisher invents their own predicates.
The cost of shared vocabularies is that you inherit their design decisions. FOAF is from 2000 — it shows its age. Dublin Core was designed for library metadata — some of its semantics do not map cleanly to digital resources. SKOS was built for thesauri — it captures concept relationships but not formal class hierarchies. schema.org is optimized for search engine consumption, not reasoning. Every vocabulary is a tradeoff, and the skill of ontology design is knowing which tradeoffs to accept and where to define something new.
Reuse before defining. Always check whether FOAF, schema.org, SKOS, dcterms, or PROV-O has an appropriate term before creating a new one in your custom namespace. New terms in a custom namespace are not shared — they are meaningful only to you until someone else adopts them.
http://xmlns.com/foaf/0.1/ · prefix: foaf:FOAF defines classes and properties for people, groups, organizations, and documents, plus the relationships between them. It was the first widely-adopted Linked Data vocabulary and remains the standard choice for representing human beings in RDF.
foaf:Person — the class for a human being (the resume subject)foaf:name, foaf:givenName, foaf:familyName — name componentsfoaf:mbox — email address (use the mailto: URI scheme)foaf:primaryTopic — links a document to the thing it is primarily aboutfoaf:knows — a weak, symmetric social connectionBoth FOAF and schema.org define person-related terms. Use foaf:Person as the class (it is more precisely human-specific than schema:Person, which also covers fictional characters). Use schema.org properties where FOAF lacks them — schema:jobTitle, schema:url, schema:telephone have no close FOAF equivalents. Mixing them on the same node is fine and common.
# A person node mixing FOAF and schema.org :alex a foaf:Person ; foaf:name "Alex Rivera" ; foaf:mbox <mailto:alex@example.com> ; schema:jobTitle "Data Scientist" . # no FOAF equivalent
http://purl.org/dc/terms/ · prefix: dcterms:Dublin Core was designed for library-style document metadata: authorship, dates, subjects, languages, rights. In an RDF graph, dcterms is the right vocabulary when you need to describe a record — a document, a dataset, a file — rather than the entity the document is about.
dcterms:title — the document's namedcterms:created — creation date (use xsd:date)dcterms:modified — last-modified datedcterms:language — the language of the document's contentdcterms:creator — who created the document (range: dcterms:Agent)dcterms:subject — what the document is aboutDublin Core has two namespaces: the original dc: (http://purl.org/dc/elements/1.1/) and the refined dcterms:. Always use dcterms:. The original dc: properties have unspecified ranges; dcterms: properties have formal semantics and are more compatible with OWL reasoning.
# The resume document node — what dcterms describes <https://sensemaking-ai.com/resume/alex-rivera/001> a sensemaking:Resume ; dcterms:title "Alex Rivera — Resume" ; dcterms:created "2024-11-01"^^xsd:date ; dcterms:language "en" ; foaf:primaryTopic :alex . # link to the person (FOAF)
The resume document and the person the resume describes are two distinct nodes. dcterms describes the document; FOAF and schema.org describe the person. foaf:primaryTopic connects them. This distinction — document vs. thing — becomes important in Module 3 when provenance tracking requires you to say who asserted a fact, in which source, at what time.
http://www.w3.org/2004/02/skos/core# · prefix: skos:SKOS represents concepts in a controlled vocabulary — a taxonomy, thesaurus, or classification scheme. A SKOS concept is a unit of meaning with preferred labels, alternative labels, and relationships to other concepts. SKOS does not make logical inferences; it organizes and navigates.
skos:Concept — a unit in a vocabulary (a skill, a job category, a subject area)skos:ConceptScheme — the vocabulary or classification system itselfskos:prefLabel — the preferred name (one per language)skos:altLabel — synonyms and abbreviationsskos:broader — the parent concept in a hierarchyskos:narrower — child conceptsskos:related — non-hierarchical conceptual associationskos:exactMatch — this concept is the same as a concept in another vocabularyskos:closeMatch — similar but not identical to a concept in another vocabularyskos:broader is not rdfs:subClassOf. In SKOS, "Machine learning is broader than Deep learning" is an organizational statement about two vocabulary concepts — not an assertion that every deep-learning instance is also a machine-learning instance in a formal reasoning sense. Use SKOS for concepts in a controlled vocabulary. Use rdfs:subClassOf for class hierarchies you want a reasoner to act on. The distinction matters in Module 2.
# A skill typed as a SKOS concept — not an OWL class :skill_python a skos:Concept ; skos:prefLabel "Python (programming language)"@en ; skos:altLabel "Python"@en ; skos:exactMatch <esco_python> ; # links into ESCO sensemaking:skillLevel "advanced" . # local property # ESCO concept stub showing the broader hierarchy <esco_python> a skos:Concept ; skos:prefLabel "use a scripting language: Python"@en ; skos:broader <esco_programming_languages> . <esco_programming_languages> a skos:Concept ; skos:prefLabel "programming languages and scripting"@en ; skos:broader <esco_ict_skills> .
https://schema.org/ · prefix: schema: · Note: use https://, not http://Schema.org is a joint vocabulary maintained by Google, Microsoft, Yahoo, and Yandex for annotating web pages so search engines can understand their content. It has extremely broad coverage — thousands of types and properties — with a deliberate emphasis on practical usability over formal precision. An organization with a name, a product with a price, a job posting with a salary range: schema.org has a type for it.
schema:Organization — a company, institution, or groupschema:CollegeOrUniversity — subclass of Organizationschema:name — name of a thing (more permissive than foaf:name)schema:jobTitle — a person's current or most recent roleschema:description — freetext description of anythingschema:url — a web addressschema:DateTime — datetime value type (used with xsd:date)Schema.org is excellent when FOAF or dcterms lacks a property you need — which is often. Its weakness is loose semantics: ranges are very permissive, and the vocabulary is not well-suited to OWL reasoning. Use it for things you want to be web-readable and broadly understood. Avoid it as your primary design surface if you need formal inference or tight constraint validation.
ESCO — the European Skills, Competences, Qualifications and Occupations framework — is published as RDF using SKOS and OWL. Approximately 3,000 occupation concepts and 14,000 skill concepts, linked into a structured hierarchy, available as Linked Open Data.
This is the interop story from Sub-module 1.1, made concrete. When a resume graph types skills as skos:Concept and links them to ESCO via skos:exactMatch, those skills are no longer isolated string values — they are nodes in a graph that connects to a continent-wide occupational taxonomy maintained by the European Commission.
What that makes possible:
skos:exactMatch/skos:broader from a person's skill into the ESCO hierarchy and return the broader occupational domain — without any data migration, import, or string matching.skos:related skill to the concept, queries that traverse skos:related from the person's skill automatically reach the new concept — without changing the resume data.None of this works in a property graph where ESCO codes are string properties. The ESCO string "ccd0a1d9" is opaque — the database does not know it points to anything. The RDF version is a live connection.
# The query that demonstrates the payoff SELECT ?skillLabel ?domainLabel WHERE { <person> sensemaking:hasSkill ?skill . ?skill skos:prefLabel ?skillLabel ; skos:exactMatch/skos:broader ?domain . ?domain skos:prefLabel ?domainLabel . FILTER (LANG(?skillLabel) = "en") FILTER (LANG(?domainLabel) = "en") }
With the ESCO stubs in resume-001.ttl, this query works locally and returns the broader domain for each of Alex's three skills. With the full ESCO dataset loaded or federated, the same query reaches the entire occupational hierarchy.
Do not use owl:sameAs to link a resume skill to an ESCO concept. owl:sameAs asserts full identity — a reasoner will merge all properties from both nodes, which causes unintended entailments (your sensemaking:skillLevel property would transfer to the ESCO concept). Use skos:exactMatch, which asserts semantic equivalence for the purposes of vocabulary alignment without triggering property inheritance. This distinction matters in Module 3. Know it now.
| What you are modeling | Start here | Then add |
|---|---|---|
| A person | foaf:Person | schema: properties FOAF lacks (jobTitle, telephone) |
| A document or record | dcterms: metadata | foaf:primaryTopic to link to the subject |
| A skill, subject area, or category | skos:Concept | skos:exactMatch to ESCO or another published vocabulary |
| An organization or institution | schema:Organization (or subclass) | Custom properties if schema.org lacks them |
| An event (employment, education) | Custom class (sensemaking:Employment) | schema:Event or schema:EducationEvent as rdfs:subClassOf |
| A class hierarchy you want to reason over | rdfs:subClassOf / OWL | Not SKOS broader — SKOS is for vocabulary navigation, not logical inference |
The decision is not always clean. A skill could be modeled as a skos:Concept (appropriate for a controlled vocabulary) or as an OWL class (appropriate if you want to reason about subskills). The resume graph uses SKOS because skills here are navigation targets into ESCO — not concepts you plan to build a class hierarchy around. If Module 2's Naruto ontology needed "skill" as a class (to declare that every ninja who has the Sharingan is also a member of the Uchiha clan), OWL classes would be right. Context determines which model serves the actual use case.
http:// to https:// in 2019. Old data uses http://schema.org/; new data uses https://schema.org/. They are technically different IRIs. Always use https://schema.org/ and double-check old Turtle files you copy from tutorials.
dc:creator (the original Dublin Core). Always use dcterms:creator. The original dc: properties have no formal range; dcterms: properties are well-defined and compatible with OWL reasoning.
skos:broader does not trigger any inference. A SPARQL query that asks for all Python skills will not automatically return Deep Learning skills just because "machine learning is broader than deep learning" is stated in SKOS. Transitive closure on SKOS hierarchies requires either a property path (skos:broader+) or a reasoner with SKOS entailment rules.
owl:sameAs merges all properties from both nodes in a reasoner. skos:exactMatch is a weaker assertion of semantic equivalence without property inheritance. Use the right one.
foaf:Person is universally recognized. Most other FOAF properties are less consistently supported. For anything beyond basic person identification, prefer schema.org equivalents — they have wider validator and tooling support.
The Sub-module 1.3 workbook (1-3-workbook-resume.html) queries Alex Rivera's resume against Fuseki. Load artifacts/resume-graph/ttl/resume-001.ttl into the Fuseki mythology dataset first. The five queries apply every vocabulary covered in this synthesis — FOAF for person facts, dcterms for document metadata, sensemaking for employment events, schema.org for organizations, and SKOS for the ESCO interop query. Exercise 1.3 then asks you to build your own resume slice using the same vocabulary choices.
Re-read the Module 1 README's primary project hook. The exercise asks for one resume, ~30–50 nodes, side-by-side Cypher and SPARQL queries. Use resume-001.ttl as a structural template — you will replace Alex Rivera's employment history with your own, but the vocabulary choices (which terms come from FOAF vs schema.org vs sensemaking vs SKOS) are the same decisions you will have to make.