SPARQL avancé

Maîtrisez les techniques avancées pour interroger des graphes RDF complexes

01

📖 Introduction au SPARQL avancé

Ce tutoriel avancé vous permettra de maîtriser les fonctionnalités puissantes de SPARQL : création de nouveaux graphes, navigation dans les relations, sous-requêtes et optimisation des performances.

💡 Prérequis : Ce tutoriel suppose que vous maîtrisez les bases de SPARQL (SELECT, WHERE, FILTER, OPTIONAL). Sinon, consultez d'abord le tutoriel SPARQL débutant.
02

🏗️ Requêtes CONSTRUCT

Contrairement à SELECT qui retourne un tableau, CONSTRUCT retourne un nouveau graphe RDF. C'est idéal pour transformer ou extraire un sous-graphe.

Exemple : Extraire les relations orateurs-discours

PREFIX schema: 
PREFIX ex: 

CONSTRUCT {
  ?orateur ex:aPrononce ?discours .
  ?discours schema:title ?titre .
}
WHERE {
  ?orateur schema:author ?discours .
  ?discours schema:title ?titre .
}
Résultat : Un nouveau graphe RDF contenant les triplets construits

Exemple : Transformer une ontologie

CONSTRUCT {
  ?personne a  .
  ?personne  ?nom .
}
WHERE {
  ?personne a schema:Person ;
           schema:name ?nom .
}
# Transforme le vocabulaire Schema.org en FOAF
💡 Utilisations de CONSTRUCT :
  • ✅ Extraction de sous-graphes
  • ✅ Transformation de vocabulaires (Schema.org → FOAF)
  • ✅ Matérialisation d'inférences
  • ✅ Préparation de données pour export
03

🔄 Chemins de propriétés

Les chemins de propriétés permettent de naviguer dans le graphe sur plusieurs niveaux.

Notation des chemins :
?s ex:prop ?o → 1 niveau
?s ex:prop+ ?o → 1 ou plusieurs niveaux
?s ex:prop* ?o → 0 ou plusieurs niveaux
?s ex:prop ?o → exactement 1 niveau

Exemple 1 : Transitivité (citations en chaîne)

PREFIX ex: 

SELECT ?discours1 ?discours2
WHERE {
  ?discours1 ex:cite+ ?discours2 .
}
# Trouve tous les discours qui citent d'autres discours (directement ou indirectement)

Exemple 2 : Longueur de chemin

SELECT ?discours1 ?discours2 (COUNT(?mid) AS ?longueur)
WHERE {
  ?discours1 ex:cite ?mid .
  ?mid ex:cite* ?discours2 .
}
GROUP BY ?discours1 ?discours2
# Calcule la distance entre deux discours

Exemple 3 : Chemins alternatifs

SELECT ?orateur1 ?orateur2
WHERE {
  ?orateur1 (ex:aPrononce | ex:cite)+ ?orateur2 .
}
# Trouve les orateurs connectés par discours ou citations
04

📊 Sous-requêtes

Les sous-requêtes permettent d'imbriquer des requêtes SELECT à l'intérieur d'une requête principale.

Exemple : Orateurs avec plus de discours que la moyenne

SELECT ?nom ?nbDiscours
WHERE {
  {
    SELECT ?orateur (COUNT(?discours) AS ?nbDiscours)
    WHERE {
      ?orateur schema:author ?discours .
    }
    GROUP BY ?orateur
  }
  ?orateur foaf:name ?nom .
  FILTER(?nbDiscours > ( SELECT AVG(?c) WHERE {
    { SELECT (COUNT(?d) AS ?c) WHERE { ?o schema:author ?d } GROUP BY ?o }
  } ))
}

Exemple : Discours les plus récents par orateur

SELECT ?orateur ?titre ?date
WHERE {
  {
    SELECT ?orateur (MAX(?date) AS ?dateMax)
    WHERE {
      ?orateur schema:author ?discours .
      ?discours schema:date ?date .
    }
    GROUP BY ?orateur
  }
  ?discours schema:date ?date ;
            schema:title ?titre .
  FILTER(?date = ?dateMax)
}
05

📈 Agrégations avancées

GROUP_CONCAT - Concaténer des valeurs

SELECT ?orateur (GROUP_CONCAT(?titre; separator=", ") AS ?discours)
WHERE {
  ?orateur schema:author ?discours .
  ?discours schema:title ?titre .
}
GROUP BY ?orateur
# Résultat : "Victor Hugo" → "Les Misérables, Notre-Dame de Paris, ..."

SAMPLE - Échantillon aléatoire

SELECT ?orateur (SAMPLE(?titre) AS ?unDiscours)
WHERE {
  ?orateur schema:author ?discours .
  ?discours schema:title ?titre .
}
GROUP BY ?orateur
# Retourne un discours aléatoire par orateur

GROUP BY avec HAVING

SELECT ?orateur (COUNT(?discours) AS ?nbDiscours)
WHERE {
  ?orateur schema:author ?discours .
}
GROUP BY ?orateur
HAVING(?nbDiscours > 5)
# Orateurs avec plus de 5 discours
06

🌐 Requêtes fédérées (SERVICE)

Le mot-clé SERVICE permet d'interroger des endpoints SPARQL distants.

Exemple : Enrichissement avec DBpedia

PREFIX dbo: 

SELECT ?nom ?description
WHERE {
  # Données locales
  ?orateur foaf:name ?nom .
  
  # Données distantes (DBpedia)
  SERVICE  {
    ?dbpedia dbo:abstract ?description ;
             dbo:birthPlace ?lieu .
    FILTER(CONTAINS(?description, ?nom))
  }
}
LIMIT 10
⚠️ Attention : Les requêtes fédérées peuvent être lentes. Utilisez-les avec parcimonie et avec des limites.
07

⚡ Optimisation des performances

Bonnes pratiques

  • ✅ Utilisez LIMIT pour limiter les résultats
  • ✅ Placez les motifs les plus restrictifs en premier
  • ✅ Utilisez des filtres tôt dans la requête
  • ✅ Évitez FILTER NOT EXISTS si possible
  • ✅ Utilisez VALUES pour lier plusieurs valeurs

Optimisation : Utilisation de VALUES

SELECT ?nom ?titre
WHERE {
  VALUES ?orateur { 
                      }
  ?orateur foaf:name ?nom ;
           schema:author ?discours .
  ?discours schema:title ?titre .
}
# Plus efficace que plusieurs FILTER ou UNION
💡 Outils d'optimisation :
  • 📊 Analyse du plan d'exécution (EXPLAIN)
  • 📈 Monitoring des temps de requête
  • 🗂️ Indexation des triple stores
08

🏋️ Exercices pratiques

Exercice 1

Créez un graphe contenant tous les orateurs nés au XIXe siècle et leurs discours.

Voir la solution
PREFIX schema: 
PREFIX foaf: 
PREFIX xsd: 

CONSTRUCT {
  ?orateur foaf:name ?nom ;
           schema:birthDate ?date ;
           schema:author ?discours .
  ?discours schema:title ?titre .
}
WHERE {
  ?orateur foaf:name ?nom ;
           schema:birthDate ?date ;
           schema:author ?discours .
  ?discours schema:title ?titre .
  FILTER(?date > "1800-01-01"^^xsd:date && ?date < "1900-01-01"^^xsd:date)
}

Exercice 2

Trouvez tous les chemins de citation entre deux discours (limite à 3 niveaux).

Voir la solution
SELECT ?chemin
WHERE {
  VALUES (?debut ?fin) { (ex:Appel18Juin ex:DiscoursX) }
  ?debut ex:cite? ?mid1 .
  ?mid1 ex:cite? ?mid2 .
  ?mid2 ex:cite? ?fin .
  BIND(CONCAT(STR(?debut), " -> ", STR(?mid1), " -> ", STR(?mid2), " -> ", STR(?fin)) AS ?chemin)
}
FILTER(?debut != ?fin)

Exercice 3

Enrichissez vos données locales avec Wikidata pour obtenir les descriptions des orateurs.

Voir la solution
SELECT ?nom ?description
WHERE {
  ?orateur foaf:name ?nom .
  SERVICE  {
    ?wikidata rdfs:label ?nom ;
              schema:description ?description .
    FILTER(LANG(?description) = "fr")
  }
}
LIMIT 20
🚀 Prochain tutoriel : 📖 Créer un système RAG →