Appearance
To build a SKOS vocabulary, you model each concept as a URI with exactly one preferred label per language, attach synonyms as alternative labels, connect concepts with broader and narrower relations, and link out to external vocabularies with mapping properties. SKOS turns a flat term list into reusable linked data. The discipline that matters most is keeping one prefLabel per concept per language and pointing hierarchy in a single consistent direction.
What is the SKOS data model in plain terms?
SKOS separates the concept (an idea with a URI) from its labels (strings). One concept, many labels:
turtle
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
<https://data.myarchive.org/concept/c-0042> a skos:Concept ;
skos:prefLabel "shipbuilding"@en ;
skos:altLabel "ship construction"@en ;
skos:altLabel "boatbuilding"@en ;
skos:definition "The craft and industry of constructing vessels."@en ."Ship construction" and "boatbuilding" now resolve to the same concept. This is the whole value of SKOS: synonym control through a single stable URI.
How do you build the hierarchy correctly?
Use skos:broader to point each child up to its parent, and let tools infer skos:narrower. Pick one direction and stay consistent:
turtle
<concept/c-0042> skos:broader <concept/c-0010> . # shipbuilding -> maritime industry
<concept/c-0055> skos:broader <concept/c-0042> . # caulking -> shipbuildingAvoid declaring both broader and narrower by hand for the same pair; that invites contradictions. Define one, infer the other.
What is the most common modelling mistake?
Two preferred labels in the same language. SKOS allows at most one prefLabel per language tag per concept. This is wrong:
turtle
# WRONG: two English prefLabels on one concept
<concept/c-0042> skos:prefLabel "shipbuilding"@en ;
skos:prefLabel "marine construction"@en .The fix is to promote one to altLabel. Validators like qSKOS and the SKOS Play validator flag this as an error immediately, so run them before publishing.
How do you link your vocabulary to the wider world?
This is what makes a SKOS vocabulary linked open data. Use mapping properties to connect to authorities:
| Property | Use when |
|---|---|
skos:exactMatch | Concepts are interchangeable |
skos:closeMatch | Concepts are very similar, not identical |
skos:broadMatch | External concept is broader than yours |
skos:narrowMatch | External concept is narrower than yours |
skos:relatedMatch | Associative, non-hierarchical link |
turtle
<concept/c-0042>
skos:exactMatch <http://vocab.getty.edu/aat/300053857> ;
skos:closeMatch <http://www.wikidata.org/entity/Q190053> .Use exactMatch sparingly and honestly; if the scopes differ even slightly, closeMatch is the truthful choice.
How do you group concepts into a scheme?
Every concept should belong to a skos:ConceptScheme, the named vocabulary that holds them, with top concepts marked:
turtle
<https://data.myarchive.org/scheme/maritime> a skos:ConceptScheme ;
skos:prefLabel "Maritime heritage thesaurus"@en ;
skos:hasTopConcept <concept/c-0010> .
<concept/c-0042> skos:inScheme <https://data.myarchive.org/scheme/maritime> .The scheme is the unit you publish, version and cite.
What tools should you use, and how do you publish?
You do not author SKOS by hand at scale. A practical toolchain:
- Authoring: VocBench or PoolParty for collaborative editing; a spreadsheet plus a
rdflibscript for small vocabularies. - Validation: qSKOS and the SKOS Play validator for structural checks.
- Publishing: Skosmos provides a browsable, queryable web interface over your concept scheme.
A spreadsheet-to-SKOS conversion in Python keeps the mapping versioned:
python
from rdflib import Graph, URIRef, Literal, Namespace
SKOS = Namespace("http://www.w3.org/2004/02/skos/core#")
g = Graph()
for row in terms:
c = URIRef(f"https://data.myarchive.org/concept/{row['id']}")
g.add((c, SKOS.prefLabel, Literal(row["pref"], lang="en")))
for syn in row["alts"]:
g.add((c, SKOS.altLabel, Literal(syn, lang="en")))
g.serialize("thesaurus.ttl", format="turtle")Key Takeaways
- A SKOS concept is a URI; labels are strings attached to it.
- Allow exactly one prefLabel per language per concept; everything else is an altLabel.
- Build hierarchy with skos:broader in one direction and let tools infer narrower.
- Link out with exactMatch, closeMatch and broad/narrowMatch to Getty, LCSH and Wikidata.
- Group concepts into a versioned skos:ConceptScheme with declared top concepts.
- Author in VocBench or a script, validate with qSKOS, and publish with Skosmos.
Frequently Asked Questions
What is SKOS used for?
SKOS (Simple Knowledge Organization System) is a W3C standard for publishing thesauri, taxonomies and controlled vocabularies as linked data, so each concept has a URI and can be reused and linked across datasets.
What is the difference between a concept and its label?
In SKOS the concept is the URI-bearing idea; labels are strings attached to it. Each concept has one prefLabel per language and any number of altLabels, so synonyms point to a single stable concept.
Should I use broader or narrower to build hierarchy?
Use skos:broader pointing from child to parent; narrower is its inverse and many tools infer it automatically. Define one direction consistently to avoid contradictory hierarchies.
How do I link my vocabulary to others?
Use the mapping properties: skos:exactMatch for identical concepts, skos:closeMatch for near matches, and broadMatch or narrowMatch for hierarchical relations to terms in Getty AAT, LCSH or Wikidata.
What is the most common SKOS modelling error?
Giving one concept two prefLabels in the same language. Each concept must have at most one prefLabel per language tag; extra preferred terms belong as altLabels. Validation tools flag this immediately.
What tools build SKOS without hand-writing RTF?
Skosmos for publishing, VocBench or the PoolParty editor for collaborative authoring, and rdflib or a spreadsheet-to-SKOS script for conversion. qSKOS and the SKOS validator catch structural faults.