
Introduction
Odeuropa is a project that studies the history of scents in Europe, collecting and analyzing representations of scents depicted in paintings, literature, and other historical sources. This article introduces the implementation of a web application for visualizing scent data based on the SKOS (Simple Knowledge Organization System) vocabulary, utilizing Odeuropa’s SPARQL endpoint.
https://odeuropa-seven.vercel.app/ja/
Project Overview
Technology Stack
- Frontend: Next.js 15 (App Router)
- UI: Material-UI v5
- Internationalization: next-intl
- Data Retrieval: SPARQL queries (Odeuropa SPARQL endpoint)
- Language: TypeScript
- Hosting: Static Site Generation (SSG)
Main Features
1. Scent Search (/odeuropa-sources)
This is the core feature of the application, allowing users to search and browse smell perception events collected by the Odeuropa project.
Key Features:
- Data retrieval via complex SPARQL queries
- Joins smell emission events, smell objects, sources (paintings, literary works, etc.), and text fragments
- Utilizes CRM-based ontology (
ecrm:P67_refers_to,od:F1_generated, etc.)
- Multi-axis filtering
- Filter by smell source using SKOS vocabulary (
?xparameter) - Source type filter (visual items
E36_Visual_Item/ linguistic objectsE33_Linguistic_Object)
- Filter by smell source using SKOS vocabulary (
- Rich information display
- Smell labels, source information (title, image, URI)
- Text fragment citations
- Qualitative information about olfactory experiences
- Pagination - Efficient display of 20 items at a time
Example SPARQL Query:
SELECT DISTINCT ?source ?source_title ?fragment ?fragment_value
?emission ?smell ?smell_label ?source_image
WHERE {
?emission od:F3_had_source ?x .
?emission od:F1_generated ?smell .
# Relation to source (via fragment or direct)
{
?fragment ecrm:P67_refers_to ?emission .
?fragment rdf:value ?fragment_value .
?source ecrm:P165_incorporates ?fragment .
} UNION {
?source ecrm:P67_refers_to ?emission .
}
}
2. Scent Detail Page (/odeuropa-sources/item)
A page that displays detailed information about individual scents.
Displayed Information:
- Basic Information
- Scent URI, label
- Link to Wikidata (
owl:sameAs) - Smell source
- Related Sources
- List of multiple sources (paintings, literary works, etc.)
- Image, title, and URI for each source
- Text fragment citations
- Detailed olfactory experience information
- Metadata
- Temporal information (
time:hasTime) - Author, creation date, language
- Temporal information (
Implementation Points:
// Get smell URI from URL parameters
const smellUri = searchParams.get('uri');
// SPARQL query to get smell details
const getSmellDetailQuery = (uri: string) => `
SELECT ?smell ?smell_label ?smell_source ?source ?source_title ...
WHERE {
BIND(<${uri}> AS ?smell)
# Get all information related to the smell
}
`;
3. Concept List (/concepts)
Displays SKOS Top Concepts, providing an overview of the scent vocabulary system.
Key Features:
- Displays only SKOS Top Concepts (
skos:topConceptOf) - Metadata display including images, alternative labels, and Wikidata links
- Display of child concept counts
- Button to navigate to the hierarchy tree
- Alphabetical sorting
4. Hierarchy Tree (/hierarchy)
Enables interactive exploration of the hierarchical structure of smell sources.
Key Features:
- Dynamic visualization of hierarchical structure
- Efficient data retrieval through lazy loading
- Flexible root specification via
?top=URIparameter - Color coding by level
- Links from each node to scent search
5. Collections (/collections)
Displays SKOS Collections, allowing browsing of smell sources grouped by theme.
Key Features:
- List display of SKOS Collections
- Display of member counts
- Search within collection members
Odeuropa’s Data Structure and SPARQL
Data Model Overview
The Odeuropa project uses its own ontology (Odeuropa Data Model), an extension of CIDOC-CRM (Conceptual Reference Model). The main entities and relationships are as follows:
1. Scent Event Model
# Smell Emission Event
?emission a od:L11_Smell_Emission ;
od:F3_had_source ?smellSource ; # Smell source
od:F1_generated ?smell ; # Generated smell
time:hasTime ?timeInterval . # Temporal information
# Smell Object
?smell a od:L1_Smell ;
rdfs:label ?smellLabel ; # Label
od:has_smell_source ?source . # Reference to smell source
# Smell Source (SKOS vocabulary)
?smellSource a skos:Concept ;
skos:prefLabel ?prefLabel ;
skos:broader ?broaderConcept ;
skos:narrower ?narrowerConcept .
2. Relationship Between Sources and Text Fragments
# Source (paintings, literary works, etc.)
?source a ecrm:E36_Visual_Item ; # or E33_Linguistic_Object
rdfs:label ?sourceTitle ;
schem:image ?sourceImage ;
ecrm:P165_incorporates ?fragment . # Contains text fragment
# Text Fragment
?fragment a ecrm:E33_Linguistic_Object ;
rdf:value ?fragmentValue ; # Actual text
ecrm:P67_refers_to ?emission . # Reference to smell emission event
3. Olfactory Experience
# Olfactory experience assignment
?experienceAssignment a ecrm:E13_Attribute_Assignment ;
ecrm:P140_assigned_attribute_to ?smell ;
ecrm:P141_assigned ?quality .
# Qualitative information
?quality rdfs:label "pleasant"@en .
Main Vocabularies and Prefixes Used
PREFIX schem: <https://schema.org/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX ecrm: <http://erlangen-crm.org/current/>
PREFIX olf: <http://data.odeuropa.eu/vocabulary/olfactory-objects/>
PREFIX od: <http://data.odeuropa.eu/ontology/>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX time: <http://www.w3.org/2006/time#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
Description of Main Vocabularies:
| Prefix | Purpose |
|---|---|
od: | Odeuropa’s custom ontology (smell emission, smell generation, etc.) |
ecrm: | CIDOC-CRM (metadata standard for cultural heritage) |
skos: | SKOS (knowledge organization system, classification of smell sources) |
schem: | Schema.org (basic metadata such as images, authors, dates) |
time: | OWL-Time (temporal information) |
owl: | OWL (identity links to Wikidata, etc.) |
SPARQL Query Implementation
1. Scent Search Query Implementation
The scent search feature executes complex queries that span multiple entities.
Basic Query Structure
PREFIX od: <http://data.odeuropa.eu/ontology/>
PREFIX ecrm: <http://erlangen-crm.org/current/>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
SELECT DISTINCT ?source ?source_title ?fragment ?fragment_value
?emission ?smell ?smell_label ?source_image
WHERE {
# 1. Smell emission event (filter condition)
?emission od:F3_had_source ?x .
# 2. Smell object generation
?emission od:F1_generated ?smell .
OPTIONAL {
?smell rdfs:label ?smell_label .
}
# 3. Relation to source (two patterns)
{
# Pattern 1: Via fragment
?fragment ecrm:P67_refers_to ?emission .
?fragment rdf:value ?fragment_value .
?source ecrm:P165_incorporates ?fragment .
?source rdfs:label ?source_title .
} UNION {
# Pattern 2: Direct reference
?source ecrm:P67_refers_to ?emission .
?source rdfs:label ?source_title .
}
# 4. Source image (optional)
OPTIONAL {
?source schem:image ?source_image .
FILTER(STRSTARTS(STR(?source_image), "https://data.odeuropa.eu/image/"))
}
}
LIMIT 20
OFFSET 0
Filtering Implementation
Filter by SKOS vocabulary (?x parameter):
# Filter by specified concept and its descendants
{
?x skos:broader* <http://data.odeuropa.eu/vocabulary/olfactory-objects/405> .
} UNION {
# Also include the specified concept itself
FILTER(?x = <http://data.odeuropa.eu/vocabulary/olfactory-objects/405>)
}
skos:broader* is a property path that recursively follows hierarchical relationships. This means that specifying “Food” will also include descendant concepts such as “Bread” and “Meat” in the search.
Filter by source type:
# Visual items only (paintings, etc.)
?source rdf:type <http://erlangen-crm.org/current/E36_Visual_Item> .
# Or linguistic objects only (literary works, etc.)
?source rdf:type <http://erlangen-crm.org/current/E33_Linguistic_Object> .
Performance Considerations
The initial implementation used GROUP_CONCAT to aggregate data, but performance issues caused timeouts. Currently, simple queries are used, and data is processed on the client side:
// Client-side data mapping
const items = data.results.bindings.map((binding) => ({
emissionUri: binding.emission.value,
sourceUri: binding.source?.value,
sourceTitle: binding.source_title?.value,
sourceImageUrl: binding.source_image?.value,
smellLabel: binding.smell_label?.value,
// ...
}));
2. Retrieving Hierarchical Relationships
This is the query for retrieving the hierarchical structure of the SKOS vocabulary. In the Odeuropa data, hierarchical relationships between concepts are expressed in multiple ways:
skos:broader- Child-to-parent referenceskos:narrower- Parent-to-child referenceskos:topConceptOf- Top concept declaration
UNION is used to handle all of these.
Multilingual Support
Since SKOS labels are stored with language tags, the appropriate language is selected on the client side.
Performance Optimization
1. Vocabulary Prefix Filtering
FILTER(STRSTARTS(...)) is used to retrieve only the necessary data from the entire dataset.
2. Lazy Loading
In the hierarchy tree, only the top level is retrieved on initial display, and child nodes are fetched only when the user expands a node.
3. Query Pre-display
To allow users to check the SPARQL query, the query is displayed before the results are returned.
UI and UX
Modern Design with Material-UI
- Improved visibility through card-based layouts
- Hover effects and transitions
- Responsive design (Grid / Flexbox)
Hierarchical Structure Visualization
- Expandable/collapsible tree structure
- Color coding by level
- Display of child concept counts
Internationalization (i18n)
English and Japanese are supported using next-intl.
Routing and Navigation
Flexible Display via Dynamic Parameters
On the hierarchy tree page, the starting concept can be specified via URL parameters.
i18n Routing Considerations
Locale-aware routing uses useRouter from @/i18n/routing.
Data Model
TypeScript Type Definitions
Type-safe handling of SPARQL response data is achieved through TypeScript interfaces.
SPARQL Response Processing
Data from the same concept spanning multiple rows is merged on the client side.
Future Outlook
- Search Functionality Expansion
- Full-text search
- Faceted search
- Detailed filters
- Visualization Enhancement
- Network graphs
- Timeline display
- Geographic distribution maps
- Data Enrichment
- Integration with other SPARQL endpoints
- Utilization of Linked Open Data
- User-generated content
Summary
In this project, we effectively visualized scent data with complex hierarchical structures using SKOS vocabularies and SPARQL. By adopting Semantic Web standards:
- Data interoperability is improved
- A highly extensible architecture is achieved
- Multilingual support is facilitated
We will continue to improve usability and enrich the data while aiming to contribute to scent history research through this platform.
Links
This article was generated with Claude Code.