A Scholarly Technical Report
MeAd (Medical Web Advisor) is a web-based platform designed to provide high-school students with an educational experience exploring medical conditions and understanding how health topics connect to population context in specific geographic regions. The solution combines a React-based single-page application frontend with multiple Spring Boot microservices that provide structured data and enrichment from external knowledge bases.
The project implements a comprehensive RDF-based knowledge model using the schema.org vocabulary, with data
stored in Apache Jena datasets and exposed via RESTful APIs. The system enriches entities dynamically using
SPARQL queries against the Wikidata and DBpedia public endpoints, employing asynchronous parallel fetching
with Java's CompletableFuture for optimal performance.
The architecture consists of two primary microservices: mead-conditions-service managing medical conditions with external knowledge enrichment, and mead-geography-service handling geographic locations (continents, countries, cities) with Linked Data connections. Both services expose SPARQL endpoints enabling direct RDF querying, ensuring full compatibility with Linked Data principles.
Medical education for high-school students often lacks interactive, structured exploration tools that connect health conditions to real-world geographic and demographic context. MeAd addresses this gap by providing a multimedia experience that allows students to explore:
The platform is built around a microservices architecture with the following components:
| Layer | Technology | Purpose |
|---|---|---|
| Frontend | React 18, Vite, React Router | Single-page application with component-based UI |
| Backend | Spring Boot 3.x, Java 17+ | RESTful microservices with dependency injection |
| RDF Storage | Apache Jena | In-memory RDF dataset with transaction support |
| Data Format | Turtle (.ttl), JSON-LD compatible | RDF serialization and API responses |
| External APIs | Wikidata SPARQL, DBpedia SPARQL | Knowledge enrichment via federated queries |
The MeAd architecture is documented using the C4 model (Context, Container, Component, Code), which provides different levels of abstraction for understanding the system.
The context diagram shows the MeAd Medical Web Advisor system in relation to its users and external systems. The primary user (High-school student) accesses the platform via browser. The system interacts with multiple external data sources: Wikidata SPARQL and DBpedia SPARQL for data enrichment, WikiDoc API for medical summaries, and Wikipedia REST API for geographic summaries.
The container diagram details the main components of the MeAd system:
All containers communicate via HTTP/JSON, and the backend services query external SPARQL endpoints for additional data.
The component diagram for mead-conditions-service shows the internal architecture:
The component diagram for mead-geography-service has a similar structure:
Each service loads its RDF dataset at startup into an in-memory Apache Jena transactional dataset. The datasets are
loaded from Turtle files located under src/main/resources/rdf. For the conditions service, enrichment is performed by
contacting Wikidata and DBpedia SPARQL endpoints in parallel, then merging, normalizing, and caching results.
The internal data structures define how medical conditions and geographic locations
are represented within the application. The core data model is designed to capture essential properties,
relationships, and classifications in a structured format that aligns with schema.org vocabulary. Both
microservices use Java records for immutable data transfer objects (DTOs) and repository patterns for
data access. Each entity includes schema:sameAs links to external knowledge bases (Wikidata and DBpedia)
for Linked Data interoperability.
The primary entities in the system are MedicalCondition and Place. Each entity is associated with various attributes that describe its properties and external Linked Data links to Wikidata and DBpedia knowledge bases.
| Entity | RDF Type | Count | Service |
|---|---|---|---|
| MedicalCondition | schema:MedicalCondition |
51 conditions | mead-conditions-service |
| Place | schema:Place |
43 locations | mead-geography-service |
The conditions service uses Java records to represent data at different layers:
public record Condition(
String identifier, // Stable slug: "asthma", "type-2-diabetes"
String name, // Display label: "Asthma", "Type 2 diabetes"
List<String> sameAs // External URIs: Wikidata, DBpedia links
) {}
public record ConditionSummary(
String id, // Same as identifier
String name, // Human-readable name
List<String> sameAs // External knowledge base links
) {}
public record ConditionDetail(
String context, // "https://schema.org/"
String id, // Full URI: "https://mead.example/condition/asthma"
String type, // "MedicalCondition"
String identifier, // Slug identifier
String name, // Display name
String description, // From DBpedia/Wikidata (dbo:abstract, schema:description)
List<String> images, // Normalized image URLs from P18, dbo:thumbnail, foaf:depiction
List<String> symptoms, // From P780 (Wikidata) or dbo:symptom (DBpedia)
List<String> riskFactors, // From P5642 (Wikidata) or dbo:medicalCause (DBpedia)
List<String> sameAs, // External URIs for linked data traversal
String wikidocSnippet // Curated student-friendly summary (50 files)
) {}
// From WikidataClient
public record WikidataEnrichment(
String description,
List<String> symptoms,
List<String> riskFactors,
List<String> images
) {}
// From DbpediaClient
public record DbpediaEnrichment(
String description,
List<String> symptoms,
List<String> riskFactors,
List<String> images
) {}
The geography service manages 43 geographic locations including continents (Europe, Asia, Africa, North America, South America, Antarctica), countries (Romania, Germany, France, Spain, Italy, United States, United Kingdom, Japan, Canada, Australia, China, India, Brazil, Mexico, Egypt, South Korea), and cities (Bucharest, Berlin, Paris, Madrid, Rome, New York City, London, Tokyo, and many more).
// Repository layer
public record Region(
String identifier, // "romania", "bucharest", "europe"
String name, // "Romania", "Bucharest", "Europe"
List<String> sameAs // Wikidata/DBpedia URIs for Linked Data
) {}
// API layer
public record RegionSummary(String id, String name) {}
public record RegionDetail(
String context, // "https://schema.org/"
String id, // Full URI: "https://mead.example/region/romania"
String type, // "Place"
String identifier, // Slug identifier
String name, // Display name
List<String> sameAs // External URIs for linked data traversal
) {}
| Category | Examples | Count |
|---|---|---|
| Continents | Europe, Asia, Africa, North America, South America, Antarctica | 6 |
| Countries | Romania, Germany, France, Spain, Italy, USA, UK, Japan, Canada, Australia, China, India, Brazil, Mexico, Egypt, South Korea | 16 |
| Cities | Bucharest, Iași, Cluj-Napoca, Timișoara, Brașov, Berlin, Paris, Madrid, Rome, New York City, Washington D.C., London, Tokyo, Ottawa, Canberra, Beijing, New Delhi, Brasília, Mexico City, Cairo, Seoul | 21 |
Both microservices use Apache Jena with in-memory datasets loaded from Turtle (.ttl) files at startup. Data is stored as RDF triples (subject-predicate-object).
Example (Turtle format):
@prefix schema: <https://schema.org/> .
@prefix condition: <https://mead.example/condition/> .
condition:asthma a schema:MedicalCondition ;
schema:identifier "asthma" ;
schema:name "Asthma"@en ;
schema:sameAs <https://www.wikidata.org/entity/Q35869>, <http://dbpedia.org/resource/Asthma> .
The conditions service has 51 medical conditions, the geography service has 43 locations -
each with schema:sameAs links to Wikidata and DBpedia.
The ontology is structured around core concepts using schema.org vocabulary. This choice ensures interoperability with the broader Semantic Web and Linked Data ecosystem, as schema.org is widely adopted by major search engines and linked data applications.
In RDF/OWL terminology, classes define the type of an entity
(used with rdf:type or a in Turtle syntax), while properties
(also called predicates) define relationships or attributes that connect
a subject to a value.
| Class | URI | Usage | Service |
|---|---|---|---|
| MedicalCondition | schema:MedicalCondition | Represents diseases, disorders, allergies (51 entities) | conditions |
| Place | schema:Place | Represents geographic locations - continents, countries, cities (43 entities) | geography |
| Property | URI | Description |
|---|---|---|
| identifier | schema:identifier | Stable slug for API access (e.g., "asthma", "romania", "bucharest") |
| name | schema:name | Human-readable label with language tags (@en) |
| sameAs | schema:sameAs | Links to external knowledge bases (Wikidata, DBpedia URIs) |
When querying external knowledge bases, the system maps to their vocabularies:
| Source | Namespace | Properties Used |
|---|---|---|
| Wikidata | wdt: (http://www.wikidata.org/prop/direct/) | P780 (symptoms), P5642 (risk factors), P18 (image) |
| DBpedia Ontology | dbo: (http://dbpedia.org/ontology/) | symptom, medicalCause, abstract, thumbnail |
| DBpedia Property | dbp: (http://dbpedia.org/property/) | symptoms, causes, complications, image |
| FOAF | foaf: (http://xmlns.com/foaf/0.1/) | depiction (images) |
The application exposes Spring Boot-based RESTful APIs that interact with the underlying RDF datasets. Each microservice provides endpoints to retrieve lists, fetch detailed information, and execute SPARQL queries against the internal knowledge graph.
The APIs follow REST architectural principles:
/conditions, /conditions/{id})application/json content typecontext, id, and type fields for semantic web compatibilityThe Conditions Service provides RESTful access to medical condition data. It serves both lightweight summaries for listing/search and enriched details that aggregate data from Wikidata, DBpedia, and WikiDoc API.
| Method | Endpoint | Description | Response |
|---|---|---|---|
GET |
/api/v1/conditions |
List all 50 medical conditions | ConditionSummary[] |
GET |
/api/v1/conditions/{id} |
Get enriched details for a specific condition | ConditionDetail |
GET |
/api/v1/health |
Health check for monitoring | {"status":"OK"} |
Lightweight representation used in list responses. Contains only essential identification data:
| Field | Type | Description |
|---|---|---|
id | string | URL-safe identifier (slug) for API access |
name | string | Human-readable condition name |
sameAs | string[] | Links to Wikidata and DBpedia entities |
Example:
GET /mead-conditions-service/api/v1/conditions
[
{ "id": "asthma", "name": "Asthma", "sameAs": ["https://www.wikidata.org/entity/Q35869", "http://dbpedia.org/resource/Asthma"] },
{ "id": "type-2-diabetes", "name": "Type 2 diabetes", "sameAs": ["https://www.wikidata.org/entity/Q3025883", "http://dbpedia.org/resource/Type_2_diabetes"] }
// ... 48 more conditions
]
Full representation with enriched data from external sources. Uses schema.org vocabulary for semantic interoperability:
| Field | Type | Source | Description |
|---|---|---|---|
context | string | static | Schema.org vocabulary reference (https://schema.org/) |
id | string | local RDF | Canonical URI for this condition |
type | string | local RDF | Always "MedicalCondition" |
identifier | string | local RDF | URL-safe slug |
name | string | local RDF | Human-readable name |
description | string | Wikidata/DBpedia | Long-form description (dbo:abstract or schema:description) |
symptoms | string[] | Wikidata/DBpedia | List of associated symptoms |
riskFactors | string[] | Wikidata/DBpedia | Contributing risk factors or causes |
images | string[] | Wikidata/DBpedia | URLs to relevant images |
sameAs | string[] | local RDF | External entity URIs (Linked Data) |
wikidocSnippet | string | WikiDoc API | Student-friendly educational summary |
Example:
GET /mead-conditions-service/api/v1/conditions/asthma
{
"context": "https://schema.org/",
"id": "https://mead.example/condition/asthma",
"type": "MedicalCondition",
"identifier": "asthma",
"name": "Asthma",
"description": "long-term disease involving inflamed airways",
"images": [
"https://commons.wikimedia.org/wiki/Special:FilePath/Asthma.jpg",
"https://commons.wikimedia.org/wiki/Special:FilePath/Asthma_attack.png"
],
"symptoms": ["wheeze", "cough", "inflammation", "chest pain"],
"riskFactors": ["air pollution", "smoking"],
"sameAs": [
"https://www.wikidata.org/entity/Q35869",
"http://dbpedia.org/resource/Asthma"
],
"wikidocSnippet": "Asthma is a long-term condition that affects the airways..."
}
The Geography Service provides RESTful access to geographic location data. It serves both lightweight summaries for listing and enriched details that aggregate data from Wikidata, DBpedia, and WikiDoc API.
| Method | Endpoint | Description | Response |
|---|---|---|---|
GET |
/api/v1/regions |
List all 43 geographic locations | RegionSummary[] |
GET |
/api/v1/regions/{id} |
Get enriched details for a specific region | RegionDetail |
GET |
/api/v1/health |
Health check for monitoring | {"status":"OK"} |
Lightweight representation used in list responses:
| Field | Type | Description |
|---|---|---|
id | string | URL-safe identifier (slug) for API access |
name | string | Human-readable location name |
type | string | Resolved type from Wikidata (country, city, continent, or Place) |
sameAs | string[] | Links to Wikidata and DBpedia entities |
Example:
GET /mead-geography-service/api/v1/regions
[
{ "id": "romania", "name": "Romania", "type": "country", "sameAs": ["https://www.wikidata.org/entity/Q218", "http://dbpedia.org/resource/Romania"] },
{ "id": "bucharest", "name": "Bucharest", "type": "city", "sameAs": ["https://www.wikidata.org/entity/Q19660", "http://dbpedia.org/resource/Bucharest"] },
{ "id": "europe", "name": "Europe", "type": "continent", "sameAs": ["https://www.wikidata.org/entity/Q46", "http://dbpedia.org/resource/Europe"] }
// ... 40 more regions
]
Full representation with enriched data from external sources:
| Field | Type | Source | Description |
|---|---|---|---|
context | string | static | Schema.org vocabulary reference |
id | string | local RDF | Canonical URI for this region |
type | string | Wikidata | Resolved type (country, city, continent, or Place) |
identifier | string | local RDF | URL-safe slug |
name | string | local RDF | Human-readable name |
description | string | Wikidata/DBpedia | Long-form description |
populationTotal | string | Wikidata/DBpedia | Total population count |
populationDensity | string | Wikidata/DBpedia | Population per km² (calculated) |
climates | string[] | Wikidata/DBpedia | Climate types (Köppen classification) |
industrialDevelopment | string[] | Wikidata/DBpedia | Major industries in the region |
culturalFactors | string[] | Wikidata/DBpedia | Languages, demonyms, cultural info |
images | string[] | Wikidata/DBpedia | URLs to relevant images |
sameAs | string[] | local RDF | External entity URIs (Linked Data) |
wikidocSnippet | string | WikiDoc API | Student-friendly educational summary |
Example:
GET /mead-geography-service/api/v1/regions/romania
{
"context": "https://schema.org/",
"id": "https://mead.example/region/romania",
"type": "country",
"identifier": "romania",
"name": "Romania",
"description": "Romania is a country in Southeastern Europe...",
"populationTotal": "19053815",
"populationDensity": "80.12",
"climates": ["humid continental climate", "oceanic climate"],
"industrialDevelopment": ["automotive industry", "information technology"],
"culturalFactors": ["Romanian", "Romanians"],
"images": ["https://commons.wikimedia.org/wiki/Special:FilePath/Romania_location_map.svg"],
"sameAs": [
"https://www.wikidata.org/entity/Q218",
"http://dbpedia.org/resource/Romania"
],
"wikidocSnippet": "Romania is a country located in southeastern Europe..."
}
This section describes the design decisions, expressiveness, and real-world usage of the RDF-based knowledge models employed by MeAd. The system uses a lightweight yet expressive ontology based on schema.org vocabulary, extended through linked data connections to established knowledge bases.
The knowledge model follows these design principles:
schema:sameAs to connect to richer external ontologies@prefix schema: <https://schema.org/> .
@prefix condition: <https://mead.example/condition/> . # Medical conditions namespace (51 entities)
@prefix region: <https://mead.example/region/> . # Geographic locations namespace (43 entities)
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> . # XML Schema datatypes
| Entity Type | URI Pattern | Example |
|---|---|---|
| Condition | https://mead.example/condition/{slug} | condition:asthma (51 entities) |
| Region/Place | https://mead.example/region/{slug} | region:romania, region:bucharest (43 entities) |
The system maintains two separate RDF knowledge graphs loaded into Apache Jena datasets:
| Metric | Count |
|---|---|
| Medical Conditions | 51 |
| External Links (sameAs) | 102 (2 per condition: Wikidata + DBpedia) |
| WikiDoc Snippets | Available for select conditions |
| Approximate Triple Count | ~260 triples |
| Metric | Count |
|---|---|
| Geographic Locations (Places) | 43 |
| Continents | 6 |
| Countries | 16 |
| Cities | 21 |
| External Links (sameAs) | 86 (2 per location: Wikidata + DBpedia) |
| Approximate Triple Count | ~220 triples |
[Knowledge graph visualization showing conditions linked to Wikidata/DBpedia. Suggested file: docs/images/knowledge-graph.png]
MeAd integrates external data using SPARQL queries against public knowledge bases. The two primary sources are Wikidata (structured, multilingual facts) and DBpedia (Wikipedia-derived knowledge), with the WikiDoc API providing curated student-friendly medical summaries.
The WikidataClient fetches enriched data from Wikidata's SPARQL endpoint.
All queries run in parallel using CompletableFuture for optimal performance.
| Data | Wikidata Property | Example (Asthma) |
|---|---|---|
| Description | schema:description | "chronic lung disease" |
| Symptoms | wdt:P780 | wheezing, coughing, chest tightness |
| Risk Factors | wdt:P5642 | allergies, air pollution, smoking |
| Images | wdt:P18 | Wikimedia Commons URLs |
SELECT DISTINCT ?symptomLabel WHERE {
wd:Q35869 wdt:P780 ?symptom .
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
} LIMIT 30
The DbpediaClient fetches Wikipedia-derived data from DBpedia's SPARQL endpoint.
It uses fallback chains to maximize data coverage when primary properties are empty.
| Data | Primary Source | Fallback |
|---|---|---|
| Description | dbo:abstract | dbo:description → rdfs:comment |
| Symptoms | dbo:symptom + rdfs:label | dbp:symptoms (literals) |
| Risk Factors | dbo:medicalCause | dbp:causes → dbp:complications |
| Images | UNION: dbo:thumbnail, foaf:depiction, schema:image, dbp:image | |
SELECT DISTINCT ?img WHERE {
{ <http://dbpedia.org/resource/Asthma> dbo:thumbnail ?img . }
UNION { <http://dbpedia.org/resource/Asthma> foaf:depiction ?img . }
UNION { <http://dbpedia.org/resource/Asthma> schema:image ?img . }
} LIMIT 10
The system uses advanced SPARQL patterns to maximize data coverage from external knowledge bases.
Fetches symptoms for a condition using Wikidata's built-in label resolution service:
PREFIX wd: <http://www.wikidata.org/entity/>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
PREFIX wikibase: <http://wikiba.se/ontology#>
PREFIX bd: <http://www.bigdata.com/rdf#>
SELECT DISTINCT ?symptomLabel WHERE {
wd:Q35869 wdt:P780 ?symptom .
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
} LIMIT 30
Pattern: The SERVICE wikibase:label automatically resolves entity URIs to human-readable labels (e.g., Q35869 → "Asthma").
Combines multiple image predicates to maximize coverage:
PREFIX dbo: <http://dbpedia.org/ontology/>
PREFIX dbp: <http://dbpedia.org/property/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX schema: <http://schema.org/>
SELECT DISTINCT ?img WHERE {
{ <http://dbpedia.org/resource/Romania> dbo:thumbnail ?img . }
UNION { <http://dbpedia.org/resource/Romania> foaf:depiction ?img . }
UNION { <http://dbpedia.org/resource/Romania> schema:image ?img . }
UNION { <http://dbpedia.org/resource/Romania> dbp:image ?img . }
} LIMIT 10
Pattern: UNION combines results from multiple predicates, ensuring images are found regardless of which property DBpedia uses.
Resolves resource URIs to human-readable labels:
PREFIX dbo: <http://dbpedia.org/ontology/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT DISTINCT ?label WHERE {
<http://dbpedia.org/resource/Romania> dbo:officialLanguage ?langResource .
?langResource rdfs:label ?label .
FILTER(LANG(?label) = "en")
} LIMIT 50
Pattern: When a property points to another resource (not a literal), we follow the link and fetch its rdfs:label for a human-readable name.
MeAd follows Tim Berners-Lee's four Linked Data principles:
| Principle | Implementation |
|---|---|
| 1. URIs as names | Each entity has a URI: https://mead.example/condition/asthma |
| 2. HTTP URIs | All URIs use HTTPS scheme, accessible via REST API |
| 3. Standard formats | RDF/Turtle storage, SPARQL endpoint, schema.org vocabulary |
| 4. Links to other URIs | schema:sameAs links to Wikidata and DBpedia for each entity |
A comprehensive video demonstration showing the MeAd Medical Web Advisor platform in action: