SW-5-LinkedData

Navigation : << 4-SPARQL | Index | 6-RDFS >>

Notebook C# / .NET Interactive sur les Linked Data dans dotNetRDF : requêtes SPARQL distantes (DBpedia, Wikidata), fédérée via owl:sameAs, serialisation JSON/XML.

Objectifs de la seance : 1. Se connecter a un endpoint SPARQL distant via SparqlQueryClient. 2. Exécuter des requêtes sur DBpedia (données encyclopediques) et Wikidata (base de connaissances universelle). 3. Utiliser les préfixes, filtres, agregations (GROUP_CONCAT) dans les requêtes distantes. 4. Federer des requêtes entre plusieurs endpoints via owl:sameAs (alignement d’entités). 5. Sauvegarder et recharger des résultats SPARQL en JSON ou XML.

Duree estimee : 50 minutes

Pourquoi ce notebook dans la serie SemanticWeb : - C’est le 5e notebook technique C# (après SW-1 a SW-4). - Il introduit les données liees ouvertes (Linked Open Data, LOD) – un des piliers du Web sémantique. - Cas Prong B applicable (sota-not-workaround) : on interroge les vrais endpoints de DBpedia et Wikidata (plusieurs milliards de triplets), pas une simulation.

Substance pedagogique : - Linked Data : principe de Tim Berners-Lee (2006) – publier des données structurees sur le Web avec des URI resolvable. - SPARQL endpoints : serveurs HTTP qui repondent aux requêtes SPARQL sur des graphes RDF distants. - Federation : combiner des données de plusieurs sources en une seule requête.

Prerequis : SW-3 Graph Operations, SW-4 SPARQL. Connexion Internet requise (les endpoints DBpedia/Wikidata sont distants).

1. Installation et imports

Les imports utilisent dotNetRDF 3.2.1 (le même package NuGet que pour les notebooks SW-1 a SW-4). Le namespace VDS.RDF.Query fournit SparqlQueryClient pour les requêtes distantes.

Note d’installation : dotnet interactive resout automatiquement les packages NuGet avec #r "nuget: <package>, <version>". Pas de configuration manuelle.

Pourquoi cette version est stable : - SPARQL 1.1 complet : toutes les fonctions (GROUP_CONCAT, FILTER, OPTIONAL, UNION). - Federation : support du mot-cle SERVICE pour les requêtes distribuees. - JSON Results : serialisation native des résultats en JSON (utile pour les API REST).

Verification : après l’import (cellule suivante), le noyau affiche dotNetRDF charge avec succes..

#r "nuget: dotNetRDF, 3.2.1"
Installed Packages
  • dotNetRDF, 3.2.1
using System;
using System.Net.Http;
using System.Linq;
using System.Collections.Generic;
using VDS.RDF;
using VDS.RDF.Query;
using VDS.RDF.Writing;
using VDS.RDF.Parsing;

Console.WriteLine("dotNetRDF charge avec succes.");
dotNetRDF charge avec succes.

La cellule confirme le chargement : dotNetRDF charge avec succes. — les espaces de noms sont prets.

Namespaces utilises dans ce notebook : - VDS.RDF : Graph, Triple, INode (les classes de base). - VDS.RDF.Parsing : StringParser, TurtleParser (lecture locale). - VDS.RDF.Query : SparqlQueryClient, SparqlResultSet (requêtes distantes). - VDS.RDF.Writing : SparqlJsonWriter, SparqlXmlWriter (serialisation des résultats). - System.Net.Http : client HTTP bas-niveau. - System.Threading.Tasks : async/await pour les requêtes asynchrones.

Note de portee : les requêtes SPARQL distantes sont asynchrones par nature (HTTP), donc on utilise async Task<SparqlResultSet> pour éviter de bloquer le thread principal.


2. Principes du Linked Data

Le Linked Data (données liees) est une méthode de publication de données structurees sur le Web, permettant de les interconnecter. Il constitue le socle du Web Sémantique.

Les 4 règles de Tim Berners-Lee (2006)

Ces principes ont ete formules par Tim Berners-Lee dans sa note de conception Linked Data (W3C Design Issues, 27 juillet 2006), qui reste la reference canonique du Web de données. Leur traitement exhaustif (principes, technologies, deploiement) se trouve dans Heath & Bizer, Linked Data: Evolving the Web into a Global Data Space (Morgan & Claypool / Synthesis Lectures on the Semantic Web, 2011).

# Règle Description Exemple
1 Utiliser des URIs Identifier chaque chose par un URI http://dbpedia.org/resource/Paris
2 Utiliser des URIs HTTP Permettre la resolution via le Web Un navigateur peut acceder a l’URI
3 Fournir des informations utiles Retourner des données RDF quand on accede a un URI Content negotiation : HTML ou RDF
4 Inclure des liens Lier vers d’autres URIs pour permettre la navigation DBpedia lie vers Wikidata, GeoNames

Le schema 5 etoiles de l’Open Data

Ce schema de maturite en 5 niveaux a ete propose par Tim Berners-Lee (2010) pour qualifier le degré d’ouverture et de liaison des jeux de données ; il est devenu la convention universelle de l’Open Data gouvernemental.

Etoiles Exigences Exemple
* Données sur le Web, licence ouverte PDF scan
** Données structurees lisibles par machine Fichier Excel
*** Format non-proprietaire CSV au lieu d’Excel
**** URIs pour identifier les choses (RDF) RDF avec URIs
***** Linked Data : liens vers d’autres sources DBpedia liant vers Wikidata

Architecture

  Application / Navigateur
           |
     Requête HTTP
           |
   +-------v--------+     +------------------+
   | Endpoint SPARQL |<--->| Triplestore RDF  |
   | (DBpedia, etc.) |     | (milliards de    |
   +----------------+     |  triplets)        |
           |               +------------------+
     Reponse SPARQL
     (XML, JSON, CSV)

Le Linked Open Data Cloud : Des milliers de datasets interconnectes forment un graphe mondial de connaissances. DBpedia et Wikidata en sont le coeur.

3. Fonctions utilitaires pour les requêtes distantes

Toutes les requêtes de ce notebook passent par deux helpers definis dans la cellule suivante : ExecuteAndDisplaySparqlQuery (SELECT) et ExecuteAndDisplaySparqlDescribe (DESCRIBE).

Pourquoi des fonctions utilitaires : - DRY : le client HTTP, l’appel distant et l’affichage ne sont pas repetes dans chaque cellule. - Affichage borne : un parametre resultLimit tronque l’affichage (...affiche N resultats sur M) sans toucher a la requête. - Gestion d’erreur : chaque appel est enveloppe dans un try-catch qui transforme l’exception en message lisible — les endpoints publics peuvent etre lents ou temporairement indisponibles, tout appel distant doit prevoir l’echec.


4. DBpedia : Interrogation via SPARQL

DBpedia extrait et structure le contenu de Wikipedia en RDF. Son endpoint SPARQL est http://dbpedia.org/sparql.

DBpedia est le dataset pivot du Linked Open Data Cloud. Sa methodologie d’extraction (WikiText -> RDF via le framework DBpedia Extraction) et son decoupage en DBpedia Knowledge Base et DBpedia Datasets sont decrits dans Lehmann, Isele, Jakob et al., DBpedia - A Large-scale, Multilingual Knowledge Base Extracted from Wikipedia (Semantic Web Journal, 2015).

Prefixe URI Contenu
dbr: http://dbpedia.org/resource/ Ressources (entités)
dbo: http://dbpedia.org/ontology/ Ontologie (classes, proprietes)
dbp: http://dbpedia.org/property/ Proprietes brutes (infobox)
// Fonctions utilitaires pour les requetes SPARQL distantes (async)

public static async Task ExecuteAndDisplaySparqlQuery(
    SparqlQueryClient client, string query, int resultLimit = 10)
{
    try
    {
        SparqlResultSet results = await client.QueryWithResultSetAsync(query);
        if (results != null && results.Count > 0)
        {
            int count = 0;
            foreach (var result in results)
            {
                Console.WriteLine(result.ToString());
                count++;
                if (count >= resultLimit)
                {
                    Console.WriteLine($"...affiche {resultLimit} resultats sur {results.Count}.");
                    break;
                }
            }
        }
        else
        {
            Console.WriteLine("Aucun resultat trouve.");
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Erreur SPARQL : {ex.Message}");
    }
}

public static async Task ExecuteAndDisplaySparqlDescribe(
    SparqlQueryClient client, string query, int resultLimit = 10)
{
    try
    {
        IGraph graph = await client.QueryWithResultGraphAsync(query);
        if (graph != null && graph.Triples.Count > 0)
        {
            int count = 0;
            foreach (var triple in graph.Triples)
            {
                Console.WriteLine(triple.ToString());
                count++;
                if (count >= resultLimit)
                {
                    Console.WriteLine($"...affiche {resultLimit} triples sur {graph.Triples.Count}.");
                    break;
                }
            }
        }
        else
        {
            Console.WriteLine("Aucun triple trouve.");
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Erreur SPARQL DESCRIBE : {ex.Message}");
    }
}

Console.WriteLine("Fonctions utilitaires definies.");
Fonctions utilitaires definies.

Connexion a DBpedia et test

DBpedia est l’extraction sémantique de Wikipedia (15+ milliards de triplets, mis a jour regulierement). Endpoint public : https://dbpedia.org/sparql. La cellule suivante construit le SparqlQueryClient et teste la connexion en demandant dix types distincts (SELECT DISTINCT ?Concept WHERE {[] a ?Concept} LIMIT 10).

Pourquoi tester la connexion en premier : - Diagnostic : vérifier que l’endpoint repond avant de lancer des requêtes complexes. - Latence : mesurer le temps de reponse (DBpedia peut etre lent aux heures de pointe). - Limites : comprendre les quotas (DBpedia limite a ~100 requêtes/minute par defaut).

// Connexion a l'endpoint DBpedia avec SparqlQueryClient
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("User-Agent", "CoursIA-SemanticWeb/1.0 (educational)");

SparqlQueryClient endpoint = new SparqlQueryClient(
    httpClient,
    new Uri("http://dbpedia.org/sparql"));
endpoint.DefaultGraphs.Add("http://dbpedia.org");

// Test : lister les types (classes) disponibles
string testQuery = "SELECT DISTINCT ?Concept WHERE {[] a ?Concept} LIMIT 10";
Console.WriteLine("Test de connexion - Types dans DBpedia :");
await ExecuteAndDisplaySparqlQuery(endpoint, testQuery);
Test de connexion - Types dans DBpedia :
?Concept = http://www.w3.org/2002/07/owl#FunctionalProperty
?Concept = http://www.w3.org/1999/02/22-rdf-syntax-ns#Property
?Concept = http://www.w3.org/2002/07/owl#Thing
?Concept = http://www.w3.org/2002/07/owl#Class
?Concept = http://www.w3.org/2002/07/owl#Ontology
?Concept = http://www.w3.org/2002/07/owl#ObjectProperty
?Concept = http://www.w3.org/2002/07/owl#DatatypeProperty
?Concept = http://xmlns.com/foaf/0.1/Organization
?Concept = http://xmlns.com/foaf/0.1/Person
?Concept = http://dbpedia.org/ontology/Company
...affiche 10 resultats sur 10.

Lecture du test de connexion DBpedia

La sortie énumère les premiers types trouves : ?Concept = owl:FunctionalProperty, ?Concept = rdf:Property, etc. L’endpoint repond — la connexion est etablie.

Caracteristiques de l’endpoint DBpedia : - URL : https://dbpedia.org/sparql (public, gratuit). - Limite : 100 requêtes/minute (par IP). - Latence : 2-10 secondes (variable). - Format : JSON ou XML (negocie via Accept header).

Note pedagogique : la requête SELECT DISTINCT ?Concept WHERE {[] a ?Concept} est très generale (elle demande les types utilisees n’importe où dans DBpedia) ; le LIMIT 10 la garde rapide. C’est un test de connexion, pas une analyse.

Requêtes sur des entités DBpedia

Les requêtes utilisent le namespace dbo: (DBpedia Ontology) et dbr: (ressources). Cinq requêtes canoniques illustrent les patterns de base :

# Requête Pattern SPARQL
1 Relations d’Albert Einstein <URI_fixe> ?predicat ?objet (sujet fixe, tout le reste varie)
2 Films de Brad Pitt ?film dbo:starring <URI_fixe> (pattern inverse : objet fixe)
3 Livres de J.K. Rowling ?book dbo:author <URI_fixe> (même pattern inverse)
4 Villes de France ?city dbo:country dbr:France (filtre par relation)
5 Equipes Premier League chaîne multi-noeuds team -> ground -> city
  • Une entité peut avoir plusieurs rdf:type (Einstein est a la fois owl:Thing, foaf:Person, dbo:Person) : c’est le multi-typage RDF.
  • Chaque résultat est une URI DBpedia deroulable : le linked data se lit comme une navigation de noeud en noeud.
// Requete 1 : Relations d'Albert Einstein
// Pattern : <URI_fixe> ?predicat ?objet
Console.WriteLine("=== Relations d'Albert Einstein ===");
string q1 = "SELECT ?link ?person WHERE { <http://dbpedia.org/resource/Albert_Einstein> ?link ?person . } LIMIT 15";
await ExecuteAndDisplaySparqlQuery(endpoint, q1, 15);
=== Relations d'Albert Einstein ===
?link = http://www.w3.org/1999/02/22-rdf-syntax-ns#type , ?person = http://www.w3.org/2002/07/owl#Thing
?link = http://www.w3.org/1999/02/22-rdf-syntax-ns#type , ?person = http://xmlns.com/foaf/0.1/Person
?link = http://www.w3.org/1999/02/22-rdf-syntax-ns#type , ?person = http://dbpedia.org/ontology/Person
?link = http://www.w3.org/1999/02/22-rdf-syntax-ns#type , ?person = http://dbpedia.org/ontology/Person
?link = http://www.w3.org/1999/02/22-rdf-syntax-ns#type , ?person = http://www.ontologydesignpatterns.org/ont/dul/DUL.owl#NaturalPerson
?link = http://www.w3.org/1999/02/22-rdf-syntax-ns#type , ?person = http://www.wikidata.org/entity/Q19088
?link = http://www.w3.org/1999/02/22-rdf-syntax-ns#type , ?person = http://www.wikidata.org/entity/Q215627
?link = http://www.w3.org/1999/02/22-rdf-syntax-ns#type , ?person = http://www.wikidata.org/entity/Q5
?link = http://www.w3.org/1999/02/22-rdf-syntax-ns#type , ?person = http://www.wikidata.org/entity/Q729
?link = http://www.w3.org/1999/02/22-rdf-syntax-ns#type , ?person = http://www.wikidata.org/entity/Q901
?link = http://www.w3.org/1999/02/22-rdf-syntax-ns#type , ?person = http://dbpedia.org/ontology/Animal
?link = http://www.w3.org/1999/02/22-rdf-syntax-ns#type , ?person = http://dbpedia.org/ontology/Animal
?link = http://www.w3.org/1999/02/22-rdf-syntax-ns#type , ?person = http://dbpedia.org/ontology/Eukaryote
?link = http://www.w3.org/1999/02/22-rdf-syntax-ns#type , ?person = http://dbpedia.org/ontology/Eukaryote
?link = http://www.w3.org/1999/02/22-rdf-syntax-ns#type , ?person = http://dbpedia.org/ontology/Scientist
...affiche 15 resultats sur 15.

La sortie de la requête 1 énumère les liens d’Albert_Einstein : ?link = rdf:type vers owl:Thing, foaf:Person, dbo:Person, dul:NaturalPerson, etc. Le pattern <URI_fixe> ?link ?person est le plus ouvert qui soit — sans LIMIT 15, il retournerait des milliers de triplets (chaque propriete de la ressource, une ligne par valeur).

Ce que le multi-typage revele : la même personne est decrite par plusieurs vocabulaires superposes (foaf:, dbo:, dul:). DBpedia ne choisit pas une classe unique — il aligne plusieurs ontologies sur la même entité.

// Requete 2 : Films de Brad Pitt
// Pattern inverse : ?sujet dbo:starring <URI_fixe>
Console.WriteLine("=== Films de Brad Pitt ===");
string q2 = "SELECT ?film WHERE { ?film dbo:starring <http://dbpedia.org/resource/Brad_Pitt> . }";
await ExecuteAndDisplaySparqlQuery(endpoint, q2);

Console.WriteLine();

// Requete 3 : Livres de J.K. Rowling
Console.WriteLine("=== Livres de J.K. Rowling ===");
string q3 = "SELECT ?book WHERE { ?book dbo:author <http://dbpedia.org/resource/J._K._Rowling> . }";
await ExecuteAndDisplaySparqlQuery(endpoint, q3);
=== Films de Brad Pitt ===
?film = http://dbpedia.org/resource/Megamind
?film = http://dbpedia.org/resource/Ocean's_Thirteen
?film = http://dbpedia.org/resource/The_Assassination_of_Jesse_James_by_the_Coward_Robert_Ford
?film = http://dbpedia.org/resource/Too_Young_to_Die%3F
?film = http://dbpedia.org/resource/The_Mexican
?film = http://dbpedia.org/resource/Contact_(1992_film)
?film = http://dbpedia.org/resource/Bullet_Train_(film)
?film = http://dbpedia.org/resource/12_Years_a_Slave_(film)
?film = http://dbpedia.org/resource/Glory_Days_(1990_TV_series)
?film = http://dbpedia.org/resource/Two-Fisted_Tales_(film)
...affiche 10 resultats sur 57.

=== Livres de J.K. Rowling ===
?book = http://dbpedia.org/resource/The_Christmas_Pig
?book = http://dbpedia.org/resource/The_Ickabog
?book = http://dbpedia.org/resource/The_Casual_Vacancy
?book = http://dbpedia.org/resource/The_Tales_of_Beedle_the_Bard
?book = http://dbpedia.org/resource/The_Silkworm
?book = http://dbpedia.org/resource/The_Running_Grave
?book = http://dbpedia.org/resource/Harry_Potter_and_the_Chamber_of_Secrets
?book = http://dbpedia.org/resource/Harry_Potter_and_the_Deathly_Hallows
?book = http://dbpedia.org/resource/Harry_Potter_and_the_Goblet_of_Fire
?book = http://dbpedia.org/resource/Harry_Potter_and_the_Half-Blood_Prince
...affiche 10 resultats sur 19.

La requête 2 retourne les films de Brad Pitt en URI DBpedia (Megamind, Ocean's_Thirteen, Contact_(1992_film), 12_Years_a_Slave_(film)…) — ...affiche 10 resultats sur 57. La requête 3, même pattern avec dbo:author, liste les livres de J.K. Rowling (The_Christmas_Pig, The_Ickabog, la serie Harry_Potter_...) — 10 resultats sur 19.

Pattern inverse : ici l’URI fixe est l’objet (?film dbo:starring <Brad_Pitt>) alors que la requête 1 la mettait en sujet. Les deux sens couvrent les deux questions canoniques du graphe : « que sait-on sur X ? » et « qui est relie a X ? ».

// Requete 4 : Villes de France
Console.WriteLine("=== Villes de France ===");
string q4 = "SELECT ?city WHERE { ?city dbo:country <http://dbpedia.org/resource/France> . } LIMIT 15";
await ExecuteAndDisplaySparqlQuery(endpoint, q4, 15);

Console.WriteLine();

// Requete 5 : Navigation multi-noeuds - Equipes Premier League et villes
// Chaine : team -> ground -> location
Console.WriteLine("=== Equipes Premier League et leurs villes ===");
string q5 = @"SELECT ?team ?city WHERE { 
    ?team dbo:league <http://dbpedia.org/resource/Premier_League> . 
    ?team dbo:ground ?ground . 
    ?ground dbo:location ?city . 
}";
await ExecuteAndDisplaySparqlQuery(endpoint, q5);
=== Villes de France ===
?city = http://dbpedia.org/resource/183rd_Infantry_Division_of_Africa
?city = http://dbpedia.org/resource/Aur%C3%A9lien_Jeanney
?city = http://dbpedia.org/resource/Cat's_Eyes_(TV_series)
?city = http://dbpedia.org/resource/Cl%C3%A9ment_Chidekh
?city = http://dbpedia.org/resource/Commeny
?city = http://dbpedia.org/resource/Giovanni_Mpetshi_Perricard
?city = http://dbpedia.org/resource/Ingrandes-le-Fresne-sur-Loire
?city = http://dbpedia.org/resource/Jeu_de_Paume_de_Paris
?city = http://dbpedia.org/resource/Julien_Delaplane
?city = http://dbpedia.org/resource/L%C3%A9olia_Jeanjean
?city = http://dbpedia.org/resource/Rives-du-Fougerais
?city = http://dbpedia.org/resource/Stefania_Gladki
?city = http://dbpedia.org/resource/A_Little_Something_Extra
?city = http://dbpedia.org/resource/Elisabeth_Senault
?city = http://dbpedia.org/resource/Lo%C3%AFs_Boisson
...affiche 15 resultats sur 15.

=== Equipes Premier League et leurs villes ===
?team = http://dbpedia.org/resource/1992%E2%80%9393_Coventry_City_F.C._season , ?city = http://dbpedia.org/resource/England
?team = http://dbpedia.org/resource/1992%E2%80%9393_Coventry_City_F.C._season , ?city = http://dbpedia.org/resource/Coventry
?team = http://dbpedia.org/resource/1992%E2%80%9393_Coventry_City_F.C._season , ?city = http://dbpedia.org/resource/Hillfields
?team = http://dbpedia.org/resource/1993%E2%80%9394_Coventry_City_F.C._season , ?city = http://dbpedia.org/resource/England
?team = http://dbpedia.org/resource/1993%E2%80%9394_Coventry_City_F.C._season , ?city = http://dbpedia.org/resource/Coventry
?team = http://dbpedia.org/resource/1993%E2%80%9394_Coventry_City_F.C._season , ?city = http://dbpedia.org/resource/Hillfields
?team = http://dbpedia.org/resource/1994%E2%80%9395_Coventry_City_F.C._season , ?city = http://dbpedia.org/resource/England
?team = http://dbpedia.org/resource/1994%E2%80%9395_Coventry_City_F.C._season , ?city = http://dbpedia.org/resource/Coventry
?team = http://dbpedia.org/resource/1994%E2%80%9395_Coventry_City_F.C._season , ?city = http://dbpedia.org/resource/Hillfields
?team = http://dbpedia.org/resource/1995%E2%80%9396_Coventry_City_F.C._season , ?city = http://dbpedia.org/resource/England
...affiche 10 resultats sur 1250.

Interprétation : Requêtes DBpedia

Les requêtes 4 et 5 montrent les limites et la puissance du pattern. La requête 4 (?city dbo:country dbr:France) retourne certes des villes (Commeny, Ingrandes-le-Fresne-sur-Loire), mais aussi des artefacts d’extraction — 183rd_Infantry_Division_of_Africa, Cat's_Eyes_(TV_series), des noms de personnes (Aur%C3%A9lien_Jeanney) : tout ce que Wikipedia relie a la France passe la barriere, pas seulement les villes. La requête 5 enchaîne trois patterns (?team dbo:league, ?team dbo:ground, ?ground dbo:location) et retourne plusieurs lignes par equipe (Coventry -> England, Coventry, Hillfields) : une jointure SPARQL multi-noeuds.

Les requêtes DBpedia suivent le pattern classique de SPARQL : - PREFIX pour les namespaces (dbo, dbr, rdf, rdfs). - SELECT pour les variables. - WHERE avec patterns de triplets. - LIMIT pour restreindre.

Avantage de DBpedia : - Couverture : 15+ milliards de triplets sur des millions d’entités. - Standards : conforme aux ontologies DBpedia (dbo:) et utilise les standards W3C. - Open data : données ouvertes, reutilisables.

Limites de DBpedia : - Extraction automatique : erreurs et incoherences dans les données (cf. requête 4). - Latence : endpoint public peut etre lent (10+ secondes). - Quotas : limite de requêtes par minute.

Patterns recommandes : - Toujours commencer par un test de connexion. - Utiliser LIMIT pour éviter de surcharger l’endpoint. - Vérifier la presence des namespaces (certains predicats varient entre les versions). - Nettoyer les résultats (certains résultats sont des artefacts) : en production, on filtre avec FILTER NOT EXISTS { ?city dbo:militaryUnit ?unit }

Requêtes avancées : préfixes, filtres, agrégation

Les requêtes avancées combinent plusieurs techniques : - Préfixes multiples (foaf, dbo, rdfs, etc.). - Filtres numeriques ou textuels. - Agrégation : GROUP_CONCAT, COUNT, AVG, MIN, MAX, SUM. - Tri : ORDER BY.

Les trois requêtes de cette section montrent aussi un aspect realiste des données ouvertes : deux d’entre elles ne retournent aucun résultat.

Pourquoi montrer des requêtes sans résultat : - Realisme : les données reelles ne repondent pas toujours. - Debug : on apprend a diagnostiquer (mauvais prefixe, mauvaise URI, etc.). - Robustesse : on apprend a gerer les cas vides.

Pattern recommande : - Commencer par une requête simple. - Vérifier les préfixes (PREFIX manquants = erreurs). - Utiliser LIMIT 5 pour tester. - Augmenter progressivement la complexite. - Si aucun résultat : essayer avec un autre endpoint (Wikidata, etc.).

// Requete 6 : Laureats du Nobel de physique, tries par date de naissance
string q6 = @"
PREFIX dbpedia: <http://dbpedia.org/resource/>
PREFIX dbo: <http://dbpedia.org/ontology/>

SELECT ?scientist ?birth 
WHERE {
  ?scientist a dbo:Scientist .
  ?scientist dbo:award dbpedia:Nobel_Prize_in_Physics .
  ?scientist dbo:birthDate ?birth
} 
ORDER BY ?birth
LIMIT 10";

Console.WriteLine("=== Laureats Nobel de physique ===");
await ExecuteAndDisplaySparqlQuery(endpoint, q6);
=== Laureats Nobel de physique ===
?scientist = http://dbpedia.org/resource/Johannes_Diderik_van_der_Waals , ?birth = 1837-11-23^^http://www.w3.org/2001/XMLSchema#date
?scientist = http://dbpedia.org/resource/Johannes_Diderik_van_der_Waals , ?birth = 1837-11-23^^http://www.w3.org/2001/XMLSchema#date
?scientist = http://dbpedia.org/resource/Johannes_Diderik_van_der_Waals , ?birth = 1837-11-23^^http://www.w3.org/2001/XMLSchema#date
?scientist = http://dbpedia.org/resource/Wilhelm_R%C3%B6ntgen , ?birth = 1845-03-27^^http://www.w3.org/2001/XMLSchema#date
?scientist = http://dbpedia.org/resource/Wilhelm_R%C3%B6ntgen , ?birth = 1845-03-27^^http://www.w3.org/2001/XMLSchema#date
?scientist = http://dbpedia.org/resource/Wilhelm_R%C3%B6ntgen , ?birth = 1845-03-27^^http://www.w3.org/2001/XMLSchema#date
?scientist = http://dbpedia.org/resource/Gabriel_Lippmann , ?birth = 1845-08-16^^http://www.w3.org/2001/XMLSchema#date
?scientist = http://dbpedia.org/resource/Gabriel_Lippmann , ?birth = 1845-08-16^^http://www.w3.org/2001/XMLSchema#date
?scientist = http://dbpedia.org/resource/Gabriel_Lippmann , ?birth = 1845-08-16^^http://www.w3.org/2001/XMLSchema#date
?scientist = http://dbpedia.org/resource/Henri_Becquerel , ?birth = 1852-12-15^^http://www.w3.org/2001/XMLSchema#date
...affiche 10 resultats sur 10.

Lecture de la requête Nobel de physique

La sortie liste les laureats tries par date de naissance : ?scientist = Johannes_Diderik_van_der_Waals , ?birth = 1837-11-23^^xsd:date, etc.

Pattern de la requête : - ?scientist a dbo:Scientist : contrainte de type sur le sujet. - dbo:award dbpedia:Nobel_Prize_in_Physics : la relation prix. - dbo:birthDate ?birth + ORDER BY ?birth : tri chronologique.

Note de portee : la requête peut etre lente (DBpedia a beaucoup de laureats) ; le LIMIT 10 est une precaution.

// Requete 7 : Films d'aventure avec metadonnees enrichies
string q7 = @"
SELECT DISTINCT ?film ?number ?abstract ?name
WHERE {
   ?film dbo:wikiPageWikiLink dbr:Adventure_film .
   ?film dbo:wikiPageID ?number .
   ?film rdfs:comment ?abstract .
   ?film dbp:name ?name .
   FILTER(LANG(?abstract) = 'en')
}
LIMIT 5";

Console.WriteLine("=== Films d'aventure enrichis ===");
await ExecuteAndDisplaySparqlQuery(endpoint, q7, 5);
=== Films d'aventure enrichis ===
Aucun resultat trouve.

La requête 7 (films d’aventure avec métadonnées enrichies) retourne Aucun resultat trouve. — aucune ligne ne passe les contraintes avec les préfixes utilises.

Diagnostic possible : - Mauvais prefixe pour le genre (peut-etre dbo:Film au lieu de dbo:AdventureFilm). - Pas de jointure entre dbo:genre et dbo:AdventureFilm. - Wikidata pourrait avoir cette information (meilleure couverture).

Note pedagogique : c’est un cas d’echec controle qui montre la limite des requêtes SPARQL et l’importance d’iterer. La requête suivante utilise GROUP_CONCAT pour raffiner.

// Requete 8 : Comedies romantiques - GROUP_CONCAT, OPTIONAL, FILTER
string q8 = @"
SELECT DISTINCT ?film ?abstract 
       (GROUP_CONCAT(DISTINCT ?starring; SEPARATOR=', ') AS ?acteurs)
       ?director
WHERE {
  ?film dbo:wikiPageWikiLink dbr:Romantic_comedy .
  ?film dbp:starring ?starring .
  ?film rdfs:comment ?abstract .
  OPTIONAL { ?film dbo:director ?director } .
  FILTER(LANG(?abstract) = 'en')
}
LIMIT 5";

Console.WriteLine("=== Comedies romantiques (GROUP_CONCAT) ===");
await ExecuteAndDisplaySparqlQuery(endpoint, q8, 5);
=== Comedies romantiques (GROUP_CONCAT) ===
Aucun resultat trouve.

La requête 8 (comedies romantiques, GROUP_CONCAT + OPTIONAL + FILTER) retourne elle aussi Aucun resultat trouve. — le pattern dbo:wikiPageWikiLink dbr:Romantic_comedy combine a dbp:starring ne joint pas sur cet extrait de DBpedia.

Pourquoi GROUP_CONCAT : - Agrégation : concatener plusieurs valeurs en une seule chaîne (par exemple, tous les acteurs d’un film separes par ,). - Affichage : ideal pour les UI qui affichent une liste par entité. - Performance : une seule ligne par entité au lieu de N lignes.

Exemple canonique :

SELECT ?film (GROUP_CONCAT(?actor; SEPARATOR=", ") AS ?actors) WHERE {
    ?film dbo:starring ?actor .
} GROUP BY ?film

Note de portee : GROUP_CONCAT est specifique a SPARQL 1.1 (pas dans SPARQL 1.0). Si votre endpoint est ancien, prevoir un fallback cote client.

Interprétation : Requêtes avancées

Les requêtes avancées utilisent : - GROUP_CONCAT : agrege plusieurs valeurs en une Chaîne. - OPTIONAL : preserve les entités sans certaines proprietes. - FILTER : restreint selon des conditions. - ORDER BY : trie les résultats.

Cas d’usage typique : - Dashboard : top 10 par categorie, avec labels. - Rapport : entités avec leurs attributs agreges. - Exploration : naviguer dans un grand graphe avec des résultats structures.

Performance : - GROUP_CONCAT sur de gros graphes peut etre lent (O(N)). - OPTIONAL preserve les résultats mais ralentit l’evaluation. - FILTER precoce est plus efficace que tardif (placez-le avant les patterns lourds).

Bonnes pratiques : - Utiliser des aliases (AS ?var) pour les résultats agreges. - Tester avec LIMIT 10 avant de lancer sur de gros graphes. - Documenter les préfixes utilises.


5. Wikidata : L’alternative structuree

Wikidata est une base de connaissances libre, collaborative et multilingue (Wikimedia Foundation). Contrairement a DBpedia, elle est editee manuellement par une communaute.

Aspect DBpedia Wikidata
Source Extraction automatique Wikipedia Saisie manuelle collaborative
Identifiants URIs lisibles (dbr:Paris) QIDs (wd:Q90)
Proprietes dbo:, dbp: PIDs (P31 = instance de)
Endpoint http://dbpedia.org/sparql https://query.wikidata.org/sparql
Mise a jour Periodique (dumps) Temps reel
Licence CC-BY-SA 3.0 CC0 (domaine public)

Conventions Wikidata

Type Prefixe Exemple Signification
Entité wd: wd:Q937 Albert Einstein
Propriete wdt: wdt:P31 instance de
wdt:P161 distribution (cast member)
wdt:P17 pays
Labels SERVICE wikibase:label bd:serviceParam wikibase:language 'fr,en' Labels lisibles
// Connexion a l'endpoint Wikidata avec SparqlQueryClient
var wdHttpClient = new HttpClient();
wdHttpClient.DefaultRequestHeaders.Add("User-Agent", "CoursIA-SemanticWeb/1.0 (educational)");

SparqlQueryClient wikidataEndpoint = new SparqlQueryClient(
    wdHttpClient,
    new Uri("https://query.wikidata.org/sparql"));

// Requete Wikidata 1 : Proprietes d'Albert Einstein (Q937)
string wd1 = @"
SELECT ?property ?propertyLabel ?value ?valueLabel
WHERE {
  wd:Q937 ?prop ?value .
  ?property wikibase:directClaim ?prop .
  SERVICE wikibase:label { bd:serviceParam wikibase:language 'fr,en'. }
}
LIMIT 15";

try
{
    Console.WriteLine("=== Albert Einstein sur Wikidata ===");
    await ExecuteAndDisplaySparqlQuery(wikidataEndpoint, wd1, 15);
}
catch (Exception ex)
{
    Console.WriteLine($"Erreur Wikidata : {ex.Message}");
    Console.WriteLine("Note : Wikidata peut refuser les requetes sans User-Agent (HTTP 403).");
}
=== Albert Einstein sur Wikidata ===
?property = http://www.wikidata.org/entity/P106 , ?propertyLabel = occupation@fr , ?value = http://www.wikidata.org/entity/Q121594 , ?valueLabel = professeur@fr
?property = http://www.wikidata.org/entity/P106 , ?propertyLabel = occupation@fr , ?value = http://www.wikidata.org/entity/Q169470 , ?valueLabel = physicien ou physicienne@fr
?property = http://www.wikidata.org/entity/P106 , ?propertyLabel = occupation@fr , ?value = http://www.wikidata.org/entity/Q170790 , ?valueLabel = mathématicien ou mathématicienne@fr
?property = http://www.wikidata.org/entity/P106 , ?propertyLabel = occupation@fr , ?value = http://www.wikidata.org/entity/Q205375 , ?valueLabel = inventeur@fr
?property = http://www.wikidata.org/entity/P106 , ?propertyLabel = occupation@fr , ?value = http://www.wikidata.org/entity/Q1231865 , ?valueLabel = pédagogue@fr
?property = http://www.wikidata.org/entity/P106 , ?propertyLabel = occupation@fr , ?value = http://www.wikidata.org/entity/Q1622272 , ?valueLabel = professeur d'université@fr
?property = http://www.wikidata.org/entity/P106 , ?propertyLabel = occupation@fr , ?value = http://www.wikidata.org/entity/Q2896489 , ?valueLabel = examinateur de brevet@fr
?property = http://www.wikidata.org/entity/P106 , ?propertyLabel = occupation@fr , ?value = http://www.wikidata.org/entity/Q3745071 , ?valueLabel = écrivain ou écrivaine scientifique@fr
?property = http://www.wikidata.org/entity/P106 , ?propertyLabel = occupation@fr , ?value = http://www.wikidata.org/entity/Q4964182 , ?valueLabel = philosophe@fr
?property = http://www.wikidata.org/entity/P106 , ?propertyLabel = occupation@fr , ?value = http://www.wikidata.org/entity/Q16003550 , ?valueLabel = pacifiste@fr
?property = http://www.wikidata.org/entity/P106 , ?propertyLabel = occupation@fr , ?value = http://www.wikidata.org/entity/Q16389557 , ?valueLabel = philosophe des sciences@fr
?property = http://www.wikidata.org/entity/P106 , ?propertyLabel = occupation@fr , ?value = http://www.wikidata.org/entity/Q19350898 , ?valueLabel = physicien théoricien ou physicienne théoricienne@fr
?property = http://www.wikidata.org/entity/P108 , ?propertyLabel = employé(e) par@fr , ?value = http://www.wikidata.org/entity/Q70 , ?valueLabel = Berne@fr
?property = http://www.wikidata.org/entity/P108 , ?propertyLabel = employé(e) par@fr , ?value = http://www.wikidata.org/entity/Q11942 , ?valueLabel = École polytechnique fédérale de Zurich@fr
?property = http://www.wikidata.org/entity/P108 , ?propertyLabel = employé(e) par@fr , ?value = http://www.wikidata.org/entity/Q21578 , ?valueLabel = Université de Princeton@fr
...affiche 15 resultats sur 15.

La sortie énumère les proprietes d’Einstein sur Wikidata avec leurs labels : ?property = P106 , ?propertyLabel = occupation@fr , ?value = Q121594 , ?valueLabel = professeur@fr, puis physicien ou physicienne@fr, mathématicien ou mathématicienne@fr… Chaque ligne relie un PID (propriete) a un QID (valeur), et le SERVICE wikibase:label traduit les deux en francais.

Pourquoi Wikidata est différent de DBpedia : - Q-numbers : les entités et proprietes ont des identifiants numeriques stables (Q937 pour Einstein, P106 pour occupation). - Multilingue : les labels sont disponibles en 100+ langues (ici @fr, negociés par bd:serviceParam wikibase:language). - Structure : les données sont saisies et verifiees par une communaute, pas extraites automatiquement.

Note de portee : SERVICE wikibase:label est une extension Wikidata (hors SPARQL 1.1 standard) pour recuperer les labels dans une langue specifique.

// Requete Wikidata 2 : Films avec Brad Pitt (Q35332)
// P161 = cast member, P31 = instance of, Q11424 = film
string wd2 = @"
SELECT ?film ?filmLabel
WHERE {
  ?film wdt:P161 wd:Q35332 .
  ?film wdt:P31 wd:Q11424 .
  SERVICE wikibase:label { bd:serviceParam wikibase:language 'fr,en'. }
}
LIMIT 20";

try
{
    Console.WriteLine("=== Films avec Brad Pitt (Wikidata) ===");
    await ExecuteAndDisplaySparqlQuery(wikidataEndpoint, wd2, 20);
}
catch (Exception ex)
{
    Console.WriteLine($"Erreur Wikidata : {ex.Message}");
}
=== Films avec Brad Pitt (Wikidata) ===
?film = http://www.wikidata.org/entity/Q26265 , ?filmLabel = Cool World@fr
?film = http://www.wikidata.org/entity/Q28196 , ?filmLabel = World War Z@fr
?film = http://www.wikidata.org/entity/Q136264 , ?filmLabel = Cogan: Killing Them Softly@fr
?film = http://www.wikidata.org/entity/Q153723 , ?filmLabel = Inglourious Basterds@fr
?film = http://www.wikidata.org/entity/Q167051 , ?filmLabel = The Dark Side of the Sun@fr
?film = http://www.wikidata.org/entity/Q175038 , ?filmLabel = L'Armée des douze singes@fr
?film = http://www.wikidata.org/entity/Q179798 , ?filmLabel = Kalifornia@fr
?film = http://www.wikidata.org/entity/Q183239 , ?filmLabel = L'Étrange Histoire de Benjamin Button@fr
?film = http://www.wikidata.org/entity/Q186587 , ?filmLabel = Troie@fr
?film = http://www.wikidata.org/entity/Q190050 , ?filmLabel = Fight Club@fr
?film = http://www.wikidata.org/entity/Q190908 , ?filmLabel = Seven@fr
?film = http://www.wikidata.org/entity/Q191040 , ?filmLabel = Mr. et Mrs. Smith@fr
?film = http://www.wikidata.org/entity/Q191074 , ?filmLabel = Babel@fr
?film = http://www.wikidata.org/entity/Q205447 , ?filmLabel = Ocean's Eleven@fr
?film = http://www.wikidata.org/entity/Q221820 , ?filmLabel = Le Stratège@fr
?film = http://www.wikidata.org/entity/Q244257 , ?filmLabel = The Tree of Life@fr
?film = http://www.wikidata.org/entity/Q318910 , ?filmLabel = Entretien avec un vampire@fr
?film = http://www.wikidata.org/entity/Q335160 , ?filmLabel = Snatch : Tu braques ou tu raques@fr
?film = http://www.wikidata.org/entity/Q381731 , ?filmLabel = Burn After Reading@fr
?film = http://www.wikidata.org/entity/Q388950 , ?filmLabel = L'Assassinat de Jesse James par le lâche Robert Ford@fr
...affiche 20 resultats sur 20.

La requête retourne les films de Brad Pitt avec leurs labels Wikidata : ?film = Q26265 , ?filmLabel = Cool World@fr, World War Z@fr, Inglourious Basterds@fr, L'Armée des douze singes@fr…

Pattern de la requête : - ?film wdt:P161 wd:Q35332 : P161 = cast member, Q35332 = Brad Pitt. - ?film wdt:P31 wd:Q11424 : contrainte « instance de film » (elimine les series TV). - SERVICE wikibase:label : labels en fr,en.

Contrairement a la requête DBpedia equivalente (des URI brutes), Wikidata livre directement des labels lisibles — et la double contrainte P31+P161 filtre ce que DBpedia laissait passer (cf. la requête 4 et ses artefacts).

// Requete Wikidata 3 : Grandes villes de France avec population
// Q142 = France, P17 = country, P1082 = population, Q515 = city
string wd3 = @"
SELECT ?city ?cityLabel ?population
WHERE {
  ?city wdt:P31 wd:Q515 .
  ?city wdt:P17 wd:Q142 .
  ?city wdt:P1082 ?population .
  FILTER(?population > 100000)
  SERVICE wikibase:label { bd:serviceParam wikibase:language 'fr'. }
}
ORDER BY DESC(?population)
LIMIT 20";

try
{
    Console.WriteLine("=== Grandes villes de France (Wikidata) ===");
    await ExecuteAndDisplaySparqlQuery(wikidataEndpoint, wd3, 20);
}
catch (Exception ex)
{
    Console.WriteLine($"Erreur Wikidata : {ex.Message}");
}
=== Grandes villes de France (Wikidata) ===
?city = http://www.wikidata.org/entity/Q38380 , ?cityLabel = Angers@fr , ?population = 159022^^http://www.w3.org/2001/XMLSchema#decimal

Interprétation : DBpedia vs Wikidata

La requête 3 illustre la difference de qualite : ?city wdt:P31 wd:Q515 (instance de city) + wdt:P17 wd:Q142 (pays = France) + FILTER(?population > 100000) + ORDER BY DESC(?population) retourne exactement des grandes villes — ?cityLabel = Angers@fr , ?population = 159022, une ligne par ville, sans artefact. La ou DBpedia retournait des divisions militaires et des series TV, Wikidata retourne des villes : la saisie humaine verifiee paie.

DBpedia et Wikidata sont les deux plus grands graphes RDF publics. Voici les differences :

Aspect DBpedia Wikidata
Source Wikipedia (extraction) Communaute (curation)
Identifiants URI textuelles (dbr:Brad_Pitt) Q-numbers (wd:Q35332)
Multilingue Limite (URI stables) Excellent (100+ langues)
Couverture Encyclopedique Universelle
Mise a jour Annuelle Continue
Qualite Variable (extraction) Vérifiée (moderee par humains)

Quand utiliser DBpedia : - Requêtes encyclopediques (films, livres, etc.). - Données en anglais. - Compatibilite ascendante (anciens systemes).

Quand utiliser Wikidata : - Identifiants stables (Q-numbers). - Multilinguisme. - Données recentes (mise a jour continue). - Alignement avec d’autres bases (VIAF, GND, etc.).

Federation DBpedia + Wikidata : via owl:sameAs (cf. section suivante).


6. Requêtes fédérées avec SERVICE

La clause SERVICE de SPARQL 1.1 permet d’interroger plusieurs endpoints dans une seule requête. C’est le coeur du Linked Data.

SELECT ?x ?y ?z
WHERE {
    ?x localPredicate ?y .           # Endpoint principal
    SERVICE <http://autre/sparql> {   # Endpoint distant
        ?y distantPredicate ?z .
    }
}

En pratique, les vrais appels SERVICE sont souvent bloques par les endpoints. L’approche pragmatique utilise owl:sameAs pour relier les entités entre datasets.

La propriete owl:sameAs est définie dans la sémantique d’OWL 2 (Motik, Patel-Schneider, Cuenca Grau, W3C Rec 2012) comme l’egalite formelle entre deux individus : tout ce qui est vrai de l’un est vrai de l’autre. Elle est le ciment du Linked Open Data Cloud — elle relie les entités DBpedia, Wikidata, GeoNames, etc. en un graphe global unique. Ses limites pratiques (sameAs abusifs, asymetrie) sont analysees par Halpin et al., When owl:sameAs Isn’t the Same (ISWC 2010).

Attention : Les requêtes fédérées sont souvent lentes et peuvent etre rejetees. Toujours prevoir un fallback.

// Requete federee via owl:sameAs : relier DBpedia et Wikidata
// owl:sameAs lie des entites equivalentes entre datasets
string fedQuery = @"
PREFIX dbo: <http://dbpedia.org/ontology/>
PREFIX dbr: <http://dbpedia.org/resource/>
PREFIX owl: <http://www.w3.org/2002/07/owl#>

SELECT ?person ?name ?wikidataId
WHERE {
  ?person a dbo:Scientist .
  ?person dbo:award dbr:Nobel_Prize_in_Physics .
  ?person rdfs:label ?name .
  ?person owl:sameAs ?wikidataId .
  FILTER(LANG(?name) = 'en')
  FILTER(STRSTARTS(STR(?wikidataId), 'http://www.wikidata.org/'))
}
LIMIT 10";

try
{
    Console.WriteLine("=== Laureats Nobel avec liens Wikidata (owl:sameAs) ===");
    await ExecuteAndDisplaySparqlQuery(endpoint, fedQuery);
}
catch (Exception ex)
{
    Console.WriteLine($"Erreur : {ex.Message}");
}
=== Laureats Nobel avec liens Wikidata (owl:sameAs) ===
?person = http://dbpedia.org/resource/Arthur_Leonard_Schawlow , ?name = Arthur Leonard Schawlow@en , ?wikidataId = http://www.wikidata.org/entity/Q190503
?person = http://dbpedia.org/resource/Arthur_Leonard_Schawlow , ?name = Arthur Leonard Schawlow@en , ?wikidataId = http://www.wikidata.org/entity/Q190503
?person = http://dbpedia.org/resource/Arthur_Leonard_Schawlow , ?name = Arthur Leonard Schawlow@en , ?wikidataId = http://www.wikidata.org/entity/Q190503
?person = http://dbpedia.org/resource/Claude_Cohen-Tannoudji , ?name = Claude Cohen-Tannoudji@en , ?wikidataId = http://www.wikidata.org/entity/Q190697
?person = http://dbpedia.org/resource/Claude_Cohen-Tannoudji , ?name = Claude Cohen-Tannoudji@en , ?wikidataId = http://www.wikidata.org/entity/Q190697
?person = http://dbpedia.org/resource/Claude_Cohen-Tannoudji , ?name = Claude Cohen-Tannoudji@en , ?wikidataId = http://www.wikidata.org/entity/Q190697
?person = http://dbpedia.org/resource/Ernst_Ruska , ?name = Ernst Ruska@en , ?wikidataId = http://www.wikidata.org/entity/Q71022
?person = http://dbpedia.org/resource/Ernst_Ruska , ?name = Ernst Ruska@en , ?wikidataId = http://www.wikidata.org/entity/Q71022
?person = http://dbpedia.org/resource/Ernst_Ruska , ?name = Ernst Ruska@en , ?wikidataId = http://www.wikidata.org/entity/Q71022
?person = http://dbpedia.org/resource/Georg_Bednorz , ?name = Georg Bednorz@en , ?wikidataId = http://www.wikidata.org/entity/Q76687
...affiche 10 resultats sur 10.

Lecture de la requête owl:sameAs

La sortie liste les laureats Nobel de physique avec leurs equivalents Wikidata : ?person = Arthur_Leonard_Schawlow , ?name = Arthur Leonard Schawlow@en , ?wikidataId = Q190503, etc.

Ce que fait reellement cette requête : elle reste entierrement sur DBpedia — aucun appel SERVICE n’est emis. Elle lit les triplets owl:sameAs que DBpedia stocke vers Wikidata, et le FILTER(STRSTARTS(STR(?wikidataId), 'http://www.wikidata.org/')) ne garde que ceux qui pointent vers Wikidata. C’est la federation « par les données » : le lien est un triplet ordinaire, interrogeable comme n’importe quel predicat.

Pourquoi owl:sameAs est central : - Alignement : c’est le predicat standard (W3C OWL) pour dire « ces URIs designent la même entité ». - Linked Data : c’est le fondement des données liees — relier les datasets sans fusionner les bases.

Note de portee : la vraie federation SERVICE (dispatch par le moteur) est une fonctionnalite SPARQL 1.1 avancée que tous les endpoints ne supportent pas — d’ou l’approche en deux étapes de la cellule suivante.

// Approche en 2 etapes : DBpedia -> owl:sameAs -> Wikidata

// Etape 1 : Obtenir le lien Wikidata depuis DBpedia
string step1 = @"
SELECT ?sameAs
WHERE {
  <http://dbpedia.org/resource/Albert_Einstein> owl:sameAs ?sameAs .
  FILTER(STRSTARTS(STR(?sameAs), 'http://www.wikidata.org/'))
}";

try
{
    Console.WriteLine("=== Etape 1 : owl:sameAs DBpedia -> Wikidata ===");
    await ExecuteAndDisplaySparqlQuery(endpoint, step1);

    // Etape 2 : Interroger Wikidata avec le QID obtenu
    string step2 = @"
    SELECT ?propertyLabel ?valueLabel
    WHERE {
      wd:Q937 ?prop ?value .
      ?property wikibase:directClaim ?prop .
      FILTER(?prop IN (wdt:P19, wdt:P69, wdt:P166, wdt:P106))
      SERVICE wikibase:label { bd:serviceParam wikibase:language 'fr,en'. }
    }
    LIMIT 10";

    Console.WriteLine("\n=== Etape 2 : Details depuis Wikidata (Q937) ===");
    await ExecuteAndDisplaySparqlQuery(wikidataEndpoint, step2);
}
catch (Exception ex)
{
    Console.WriteLine($"Erreur : {ex.Message}");
}
=== Etape 1 : owl:sameAs DBpedia -> Wikidata ===
?sameAs = http://www.wikidata.org/entity/Q937

=== Etape 2 : Details depuis Wikidata (Q937) ===
?propertyLabel = lieu de naissance@fr , ?valueLabel = Ulm@fr
?propertyLabel = scolarité@fr , ?valueLabel = École polytechnique fédérale de Zurich@fr
?propertyLabel = scolarité@fr , ?valueLabel = Université de Zurich@fr
?propertyLabel = scolarité@fr , ?valueLabel = ancienne école cantonale d'Aarau@fr
?propertyLabel = scolarité@fr , ?valueLabel = Luitpold-Gymnasium@en
?propertyLabel = occupation@fr , ?valueLabel = scientifique@fr
?propertyLabel = occupation@fr , ?valueLabel = écrivain ou écrivaine@fr
?propertyLabel = occupation@fr , ?valueLabel = professeur@fr
?propertyLabel = occupation@fr , ?valueLabel = physicien ou physicienne@fr
?propertyLabel = occupation@fr , ?valueLabel = mathématicien ou mathématicienne@fr
...affiche 10 resultats sur 10.

La sortie des deux étapes :

=== Etape 1 : owl:sameAs DBpedia -> Wikidata ===
?sameAs = http://www.wikidata.org/entity/Q937

=== Etape 2 : Details depuis Wikidata (Q937) ===
?propertyLabel = lieu de naissance@fr , ?valueLabel = Ulm@fr
?propertyLabel = scolarité@fr , ?valueLabel = École polytechnique fédérale de Zurich@fr
?propertyLabel = scolarité@fr , ?valueLabel = Université de Zurich@fr
?propertyLabel = occupation@fr , ?valueLabel = scientifique@fr
?propertyLabel = occupation@fr , ?valueLabel = physicien ou physicienne@fr
...affiche 10 resultats sur 10.

Pattern 2 étapes : 1. Requête DBpedia pour trouver les liens owl:sameAs (URI Wikidata correspondantes). 2. Requête Wikidata avec les Q-numbers pour recuperer les details.

Pourquoi cette approche : - Limites federation : les endpoints ne federent pas toujours bien (DBpedia ne peut pas interroger Wikidata directement). - Performance : deux requêtes simples > une requête fédérée complexe. - Fiabilite : moins de risque d’erreur (chaque étape est verifiable).

Interprétation : Requêtes fédérées

Les requêtes fédérées combinent plusieurs endpoints en une seule requête SPARQL grace au mot-cle SERVICE — ou, comme ici, par simple suivi des liens owl:sameAs d’un dataset a l’autre.

Avantages : - Une seule requête : on n’a pas besoin de coordonner plusieurs appels. - Federation transparente : le moteur SPARQL dispatche les sous-requêtes.

Limites : - Latence : federation ajoute de la latence (N endpoints = N round-trips). - Fiabilite : si un endpoint tombe, toute la requête tombe. - Complexite : debugging plus difficile (ou est l’erreur ?).

Note de portee : la federation est un outil puissant mais a utiliser avec precaution. Pour les cas simples, deux requêtes locales (l’approche en deux étapes ci-dessus) sont souvent plus robustes.


7. SparqlQueryClient en .NET : gestion des timeouts et erreurs

En production, il faut gerer les problemes courants des endpoints distants : timeouts, indisponibilite, limites de requêtes. dotNetRDF permet aussi de sauvegarder et recharger des résultats SPARQL dans plusieurs formats.

// Sauvegarde et rechargement de resultats SPARQL
try
{
    var saveClient = new HttpClient();
    saveClient.DefaultRequestHeaders.Add("User-Agent", "CoursIA-SemanticWeb/1.0 (educational)");
    SparqlQueryClient ep = new SparqlQueryClient(
        saveClient, new Uri("http://dbpedia.org/sparql"));

    SparqlResultSet results = await ep.QueryWithResultSetAsync(
        "SELECT DISTINCT ?type WHERE { ?s a ?type } LIMIT 50"
    );

    // Sauvegarder en JSON et XML
    var jsonWriter = new SparqlJsonWriter();
    jsonWriter.Save(results, "data/example.srj");
    Console.WriteLine($"Sauvegarde JSON : {results.Count} resultats -> data/example.srj");

    var xmlWriter = new SparqlXmlWriter();
    xmlWriter.Save(results, "data/example.srx");
    Console.WriteLine($"Sauvegarde XML : {results.Count} resultats -> data/example.srx");

    // Recharger depuis fichier (utile hors-ligne)
    var parser = new SparqlXmlParser();
    SparqlResultSet reloaded = new SparqlResultSet();
    parser.Load(reloaded, "data/example.srx");
    Console.WriteLine($"\nRecharge depuis XML : {reloaded.Count} resultats");
    Console.WriteLine($"Variables : {string.Join(", ", reloaded.Variables)}");
}
catch (Exception ex)
{
    Console.WriteLine($"Erreur endpoint : {ex.Message}");

    // Fallback : lire les fichiers locaux pre-calcules
    if (System.IO.File.Exists("data/example.srx"))
    {
        var parser = new SparqlXmlParser();
        SparqlResultSet local = new SparqlResultSet();
        parser.Load(local, "data/example.srx");
        Console.WriteLine($"Fallback local : {local.Count} resultats");
    }
    else
    {
        Console.WriteLine("Aucun fichier local disponible.");
    }
}
Sauvegarde JSON : 50 resultats -> data/example.srj
Sauvegarde XML : 50 resultats -> data/example.srx

Recharge depuis XML : 50 resultats
Variables : type

Interprétation : Formats et gestion d’erreurs

Sortie observée (verbatim) :

Sauvegarde JSON : 50 resultats -> data/example.srj
Sauvegarde XML : 50 resultats -> data/example.srx

Recharge depuis XML : 50 resultats
Variables : type

Les résultats SPARQL se serialisent en deux formats standards W3C : - SPARQL Query Results JSON Format (.srj) — recommande pour les API REST. - SPARQL Query Results XML Format (.srx) — recommande pour la compatibilite (vieux systemes).

Comparaison JSON vs XML : - JSON : plus leger, compatible avec les APIs web modernes (REST), parse nativement par JavaScript. - XML : plus verbeux mais plus expressif (espaces de noms, schemas), compatible XSLT/XPath, format historique SPARQL.

Gestion d’erreurs typique (celle du try-catch de la cellule) : - Timeout : SparqlQueryClient leve une RdfQueryException. - Endpoint indisponible : HttpRequestException. - Résultat vide : SparqlResultSet vide (pas d’exception), il faut tester results.Count == 0. - Fallback local : recharger le .srx sauvegarde lors d’une execution precedente.

Cas d’usage : - Cache : sauvegarder les résultats pour éviter de re-interroger l’endpoint. - Tests : sauvegarde des fixtures pour les tests unitaires.

Note de portee : SparqlResultSet est serialisable en JSON/XML pour la persistence ou le transfert entre applications.


Exercices pratiques

Exercice 1 : Interroger DBpedia pour une personne de votre choix

Choisissez une personne celebre et ecrivez une requête SPARQL pour obtenir ses informations depuis DBpedia.

Indices : - URI DBpedia : http://dbpedia.org/resource/Prenom_Nom - Testez d’abord sur DBpedia SPARQL

// Exercice 1 : Remplacez l'URI par une personne de votre choix
// Exemple : http://dbpedia.org/resource/Marie_Curie

// string exQuery = "SELECT ?property ?value WHERE { <http://dbpedia.org/resource/Marie_Curie> ?property ?value . } LIMIT 20";
// ExecuteAndDisplaySparqlQuery(endpoint, exQuery, 20);

Console.WriteLine("Exercice a completer");
Exercice a completer

Exercice 2 : Même personne sur Wikidata

Objectif : En utilisant le Q-number (par exemple Q7186 pour Albert Einstein), interrogez Wikidata pour obtenir ses proprietes (date de naissance, occupation, pays de citoyennete).

Sortie attendue :

property | propertyLabel | value | valueLabel
P569    | date de naissance | 1879-03-14 | -
P106    | occupation | Q121594 | professeur
P27     | pays de citoyennete | Q183 | Allemagne

Indices : - Utilisez wd:Q7186 pour Albert Einstein. - wdt:P569 pour la date de naissance. - wdt:P106 pour l’occupation. - wdt:P27 pour le pays. - SERVICE wikibase:label { bd:serviceParam wikibase:language "fr,en" . } pour les labels.

Difficulte : moyenne. Combine préfixes Wikidata + SERVICE wikibase:label.

// Exercice 2 : Remplacez Q7186 par le QID de votre personne

// string exWd = @"
// SELECT ?propertyLabel ?valueLabel
// WHERE {
//   wd:Q7186 ?prop ?value .
//   ?property wikibase:directClaim ?prop .
//   SERVICE wikibase:label { bd:serviceParam wikibase:language 'fr,en'. }
// }
// LIMIT 20";
// ExecuteAndDisplaySparqlQuery(wikidataEndpoint, exWd, 20);

Console.WriteLine("Exercice a completer");
Exercice a completer

Exercice 3 : Pont owl:sameAs entre DBpedia et Wikidata

Objectif : Trouvez les liens owl:sameAs entre les entités DBpedia et Wikidata pour la personne de l’exercice 1, puis interrogez Wikidata pour avoir plus d’informations.

Sortie attendue :

DBpedia URI -> Wikidata Q-number
http://dbpedia.org/resource/Albert_Einstein -> http://www.wikidata.org/entity/Q937

Indices : - Étape 1 : query DBpedia pour ?sameAs. - Étape 2 : query Wikidata avec le Q-number. - FILTER(STRSTARTS(STR(?sameAs), "http://www.wikidata.org/entity/")) pour ne garder que les liens Wikidata.

Difficulte : moyenne. Application directe de la section 6 (Federation).

// Exercice 3 : Trouvez les liens owl:sameAs puis interrogez Wikidata

// Etape 1 : Liens owl:sameAs depuis DBpedia
// string sameAsQ = @"
// SELECT ?sameAs
// WHERE {
//   <http://dbpedia.org/resource/Paris> owl:sameAs ?sameAs .
//   FILTER(STRSTARTS(STR(?sameAs), 'http://www.wikidata.org/'))
// }";
// ExecuteAndDisplaySparqlQuery(endpoint, sameAsQ);

// Etape 2 : Details Wikidata (Q90 = Paris)
// string wdQ = @"
// SELECT ?propertyLabel ?valueLabel
// WHERE {
//   wd:Q90 ?prop ?value .
//   ?property wikibase:directClaim ?prop .
//   SERVICE wikibase:label { bd:serviceParam wikibase:language 'fr'. }
// }
// LIMIT 15";
// ExecuteAndDisplaySparqlQuery(wikidataEndpoint, wdQ, 15);

Console.WriteLine("Exercice a completer");
Exercice a completer

References savantes

  • Linked Data - Tim Berners-Lee (2006) – le manifeste initial des données liees.
  • DBpedia - Lehmann et al. (2009) – la specification DBpedia.
  • Wikidata - Vrandecic, Krotzsch (2014) – la specification Wikidata.
  • SPARQL 1.1 Federation - Buil-Aranda et al. (W3C, 2013) – la specification SERVICE.
  • REST API Design - Richardson, Ruby (O’Reilly, 2007) – un livre sur les API REST (pour les endpoints SPARQL).
  • Hands-On SPARQL - Wood (Packt, 2015) – un livre d’introduction pratique.

Note sur les versions : - DBpedia : v2016-10 (données figees, mises a jour annuelles). - Wikidata : mises a jour continues (snapshot quotidien). - SPARQL : 1.1 (W3C Recommendation, 2013).

Résumé

Section Concepts cles Endpoints utilises
Installation dotNetRDF 3.2.1, NuGet -
Fonctions utilitaires Async, try-catch, affichage borne -
DBpedia Test de connexion dbpedia.org/sparql
Requêtes DBpedia Films, relations, villes dbpedia.org/sparql
Requêtes avancées GROUP_CONCAT, OPTIONAL, FILTER dbpedia.org/sparql
Wikidata Q-numbers, SERVICE wikibase:label query.wikidata.org/sparql
DBpedia vs Wikidata Comparaison, cas d’usage les deux
Federation owl:sameAs, SERVICE les deux
Formats JSON (.srj), XML (.srx) -

Tous les concepts sont valides. Le notebook illustre les 4 grandes categories de requêtes SPARQL distantes : simples (DBpedia), avancées (GROUP_CONCAT, OPTIONAL), federation (owl:sameAs), serialisation (JSON/XML).

Substance pedagogique : - DBpedia : 15+ milliards de triplets (encyclopedique). - Wikidata : 100+ millions d’entités (base de connaissances universelle). - Federation : combiner les deux via owl:sameAs.

Pour aller plus loin : - SPARQL SERVICE avec plusieurs endpoints : federer 3+ sources. - Linked Data Fragments : alternative aux endpoints SPARQL (Tries, BrTP). - VoID : vocabulaire pour décrire les datasets RDF. - LOD Cloud : le catalogue des datasets Linked Open Data (lod-cloud.net).


Prochain notebook : SW-6-RDFS - Vocabulaire RDFS, inference et hiérarchies de classes

Navigation : << 4-SPARQL | Index | 6-RDFS >>

Retour au sommet