- Introduced the ImageTilingServiceEndpoint class for tiled high-resolution image delivery, including deep-zoom and transformation capabilities, with multilingual descriptions and structured aliases. - Archived the ID class as a backwards-compatible alias for Identifier, marking it as deprecated to enforce the use of the canonical Identifier model.
10 KiB
Rule 38: Slot Centralization and Semantic URI Requirements
🚨 CRITICAL: All LinkML slots MUST be centralized in model/symbolic/schema/modules/slots/ and MUST have semantically sound slot_uri predicates from base ontologies.
1. Slot Centralization is Mandatory
Location: All slot definitions MUST be in model/symbolic/schema/modules/slots/
File Naming: {slot_name}.yaml (snake_case)
Import Pattern: Classes import slots via relative imports:
# In modules/classes/Collection.yaml
imports:
- ../slots/collection_name
- ../slots/collection_type_ref
- ../slots/parent_collection
Why Centralization?
-
UML Visualization: The frontend's schema service loads slots from the database in which
modules/slots/files are ingested to determine aggregation edges. Inline slots in class files are NOT properly parsed for visualization. -
Reusability: Slots can be used by multiple classes without duplication.
-
Semantic Consistency: Single source of truth for slot semantics prevents drift.
-
Maintainability: Changes to slot semantics propagate automatically to all classes.
Anti-Pattern: Inline Slot Definitions
# ❌ WRONG - Slots defined inline in class file
classes:
Collection:
slots:
- collection_name
- parent_collection
slots: # ← This section in a class file is WRONG
collection_name:
range: string
# ✅ CORRECT - Slots imported from centralized files
# In modules/classes/Collection.yaml
imports:
- ../slots/collection_name
- ../slots/parent_collection
classes:
Collection:
slots:
- collection_name
- parent_collection
2. Every Slot MUST Have slot_uri
slot_uri provides the semantic meaning of the slot in a linked data context. It maps your slot to a predicate from an established ontology. Do avoid adding external uri in case there are no exact mapping! In this common case, the slot_uri should be a self-reference using the 'hc' prefix.
Required Slot File Structure
# Global slot definition for {slot_name}
# Used by: {list of classes}
id: https://nde.nl/ontology/hc/slot/{slot_name}
name: {slot_name}
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
# Add ontology prefixes as needed
rico: https://www.ica.org/standards/RiC/ontology#
schema: http://schema.org/
skos: http://www.w3.org/2004/02/skos/core#
slots:
{slot_name}:
slot_uri: {ontology_prefix}:{predicate} # ← REQUIRED
description: |
Description of the slot's semantic meaning.
{OntologyName}: {predicate} - "{definition from ontology}"
range: {ClassName or primitive}
required: true/false
multivalued: true/false
# Optional mappings for additional semantic relationships
exact_mappings:
- schema:alternatePredicate
close_mappings:
- dct:relatedPredicate
examples:
- value: {example}
description: {explanation}
Ontology Sources for slot_uri
Consult these base ontology files in /data/ontology/:
| Ontology | File | Namespace | Use Cases |
|---|---|---|---|
| RiC-O | RiC-O_1-1.rdf |
rico: |
Archival records, record sets, custody |
| CIDOC-CRM | CIDOC_CRM_v7.1.3.rdf |
crm: |
Cultural heritage objects, events |
| Schema.org | schemaorg.owl |
schema: |
Web semantics, general properties |
| SKOS | skos.rdf |
skos: |
Labels, concepts, mappings |
| Dublin Core | dublin_core_elements.rdf |
dcterms: |
Metadata properties |
| PROV-O | prov-o.ttl |
prov: |
Provenance tracking |
| PAV | pav.rdf |
pav: |
Provenance, authoring, versioning |
| TOOI | tooiont.ttl |
tooi: |
Dutch government organizations |
| CPOV | core-public-organisation-ap.ttl |
cpov: |
EU public sector |
| ORG | org.rdf |
org: |
Organizations, units, roles |
| FOAF | foaf.ttl |
foaf: |
People, agents, social network |
| GLEIF | gleif_base.ttl |
gleif_base: |
Legal entities |
Example: Correct Slot with slot_uri
# modules/slots/preferred_label.yaml
id: https://nde.nl/ontology/hc/slot/preferred_label
name: preferred_label_slot
prefixes:
linkml: https://w3id.org/linkml/
hc: https://nde.nl/ontology/hc/
skos: http://www.w3.org/2004/02/skos/core#
schema: http://schema.org/
rdfs: http://www.w3.org/2000/01/rdf-schema#
slots:
preferred_label:
slot_uri: skos:prefLabel # ← REQUIRED
description: |
The primary display name for this entity.
SKOS: prefLabel - "A preferred lexical label for a resource."
This is the CANONICAL name - the standardized label accepted by the
entity itself for public representation.
range: string
required: false
exact_mappings:
- schema:name
- rdfs:label
examples:
- value: "Rijksmuseum"
description: Primary display name for the Rijksmuseum
3. Mappings Can Apply to Both Classes AND Slots
LinkML provides SKOS-based mapping predicates that work on both classes and slots:
| Mapping Type | Predicate | Use Case |
|---|---|---|
exact_mappings |
skos:exactMatch |
Identical meaning |
close_mappings |
skos:closeMatch |
Very similar meaning |
related_mappings |
skos:relatedMatch |
Semantically related |
narrow_mappings |
skos:narrowMatch |
More specific |
broad_mappings |
skos:broadMatch |
More general |
When to Use Mappings vs. slot_uri
| Scenario | Use |
|---|---|
| Primary semantic identity | slot_uri (exactly one) |
| Equivalent predicates in other ontologies | exact_mappings (multiple allowed) |
| Similar but not identical predicates | close_mappings |
| Related predicates with different scope | narrow_mappings / broad_mappings |
Example: Slot with Multiple Mappings
slots:
website:
slot_uri: gleif_base:hasWebsite # Primary predicate
range: uri
description: |
Official website URL of the organization or entity.
gleif_base:hasWebsite - "A website associated with something"
exact_mappings:
- schema:url # Identical meaning in Schema.org
close_mappings:
- foaf:homepage # Similar but specifically "main" page
Example: Class with Multiple Mappings
classes:
Collection:
class_uri: rico:RecordSet # Primary class
exact_mappings:
- crm:E78_Curated_Holding # CIDOC-CRM equivalent
close_mappings:
- bf:Collection # BIBFRAME close match
narrow_mappings:
- edm:ProvidedCHO # Europeana (narrower - cultural heritage objects)
4. Workflow for Creating a New Slot
Step 1: Search Base Ontologies
Before creating a slot, search for existing predicates:
# Search for relevant predicates
rg "website|homepage|url" /data/ontology/*.ttl /data/ontology/*.rdf /data/ontology/*.owl
# Check specific ontology
rg "rdfs:label|rdfs:comment" /data/ontology/schemaorg.owl | grep -i "name"
Step 2: Document Ontology Alignment
In the slot file, document WHY you chose that predicate:
slots:
source_url:
slot_uri: pav:retrievedFrom
description: |
URL of the web page from which data was retrieved.
pav:retrievedFrom - "The URI from which the resource was retrieved."
Chosen over:
- schema:url (too generic - refers to the entity's URL, not source)
- dct:source (refers to intellectual source, not retrieval location)
- prov:wasDerivedFrom (refers to entity derivation, not retrieval)
Step 3: Create Centralized Slot File
# Create new slot file
touch schemas/20251121/linkml/modules/slots/new_slot_name.yaml
Step 4: Update Manifest
Run the manifest regeneration script or manually add to manifest:
cd schemas/20251121/linkml
python3 scripts/regenerate_manifest.py
Step 5: Import in Class Files
Add the import to classes that use this slot.
5. Validation Checklist
Before committing slot changes:
- Slot file is in
modules/slots/ - Slot has
slot_uripointing to an established ontology predicate - Predicate is from
data/ontology/files or standard vocabularies - Description includes ontology definition
- Rationale documented if multiple predicates were considered
exact_mappings/close_mappingsadded for equivalent predicates- Manifest updated to include new slot file
- Classes using the slot have been updated with import
- Frontend slot files synced:
frontend/public/schemas/20251121/linkml/modules/slots/
6. Common Slot URI Mappings
| Slot Concept | Recommended slot_uri |
Alternative Mappings |
|---|---|---|
| Preferred name | skos:prefLabel |
schema:name, rdfs:label |
| Alternative names | skos:altLabel |
schema:alternateName |
| Description | dcterms:description |
schema:description, rdfs:comment |
| Identifier | dcterms:identifier |
schema:identifier |
| Website URL | gleif_base:hasWebsite |
schema:url, foaf:homepage |
| Source URL | pav:retrievedFrom |
prov:wasDerivedFrom |
| Created date | dcterms:created |
schema:dateCreated, prov:generatedAtTime |
| Modified date | dcterms:modified |
schema:dateModified |
| Language | schema:inLanguage |
dcterms:language |
| Part of | dcterms:isPartOf |
rico:isOrWasPartOf, schema:isPartOf |
| Has part | dcterms:hasPart |
rico:hasOrHadPart, schema:hasPart |
| Location | schema:location |
locn:address, crm:P53_has_former_or_current_location |
| Start date | schema:startDate |
prov:startedAtTime, rico:hasBeginningDate |
| End date | schema:endDate |
prov:endedAtTime, rico:hasEndDate |
See Also
- LinkML slot_uri documentation
- LinkML mappings documentation
- LinkML URIs and Mappings guide
- Rule 1: Ontology Files Are Your Primary Reference
- Rule 0: LinkML Schemas Are the Single Source of Truth
Version: 1.0.0 Created: 2026-01-06 Author: OpenCODE