======== SPARQL ======== .. include:: common.inc .. only:: html .. notslides:: .. contents:: :local: :depth: 1 :backlinks: none Introduction ============ Objectifs +++++++++ * Vous donner des bases pour écrire des requêtes SPARQL. * Bonus: lire/écrire du Turtle (très proche de SPARQL). * Ce n'est qu'une introduction ; pour en savoir plus : http://www.w3.org/TR/sparql11-overview/ Requête simple ++++++++++++++ .. code-block:: sparql PREFIX foaf: SELECT ?n1 ?n2 WHERE { ?p1 a . foaf:name ?n1 ; foaf:knows ?p2 . ?p2 a foaf:Person ; foaf:name ?n2 . } .. digraph:: simpleSelectQuery graph [ rankdir="LR" margin=0 ] Person [ label="foaf:Person" ] p1 [ label="?p1" ] n1 [ label="?n1" style=filled, fillcolor=gray ] p2 [ label="?p2" ] n2 [ label="?n2" style=filled, fillcolor=gray ] p1 -> Person [ label="rdf:type" ] p1 -> n1 [ label="foaf:name" ] p1 -> p2 [ label="foaf:knows" ] p2 -> Person [ label="rdf:type" ] p2 -> n2 [ label="foaf:name" ] Exemple de données ------------------ .. digraph:: simpleDataset graph [ rankdir="LR" margin=0] Person [ label="foaf:Person" ] p1 [ label="a" ] p2 [ label="b" ] p3 [ label="c" ] p4 [ label="d" ] p5 [ label="e" ] n1 [ label="Alice" shape=box ] n2 [ label="Bob" shape=box ] n3 [ label="Carol" shape=box ] n4 [ label="Dan" shape=box ] n5 [ label="Dr Jekyll" shape=box ] n5b [ label="Mr Hyde" shape=box ] Person -> p1 [ label="rdf:type" dir=back ] Person -> p2 [ label="rdf:type" dir=back ] Person -> p3 [ label="rdf:type" dir=back ] Person -> p4 [ label="rdf:type" dir=back ] Person -> p5 [ label="rdf:type" dir=back ] p1 -> n1 [ label="foaf:name" ] p2 -> n2 [ label="foaf:name" ] p3 -> n3 [ label="foaf:name" ] p4 -> n4 [ label="foaf:name" ] p5 -> n5 [ label="foaf:name" ] p5 -> n5b [ label="foaf:name" ] # there seem to be a bug with contraint=false, # it reverses the direction of the arc in some cases, # hence the "dir=back" below p1 -> p2 [ label="foaf:knows" constraint=false dir=back ] p3 -> p4 [ label="foaf:knows" constraint=false dir=back ] p5 -> p4 [ label="foaf:knows" constraint=false ] Résultats --------- =========== ===== n1 n2 =========== ===== Alice Bob Carol Dan Dr Jekyll Dan Mr Hide Dan =========== ===== Description du graphe requête ============================= Préfixes ++++++++ Rappel : les préfixes servent à abréger les IRIs. .. code-block:: sparql PREFIX foaf: PREFIX : Termes ++++++ IRI en extension (relatif ou absolu) :: <../other-file.rdf> <#something> <> IRI abrégé :: foaf:Person :something Termes (suite) -------------- Litéral :: "Bonjour" "Hello"@en # avec tag de langue "123"^^xsd:integer # typé 42 # equiv. "42"^^xsd:integer 1.5 # equiv. "1.5"^^xsd:decimal 314e-2 # equiv. "314e-2"^^xsd:double true # equiv. "true"^^xsd:boolean Nœud muet :: _:toto [] # voir ci-après Termes (suite) -------------- Variable (SPARQL seulement) : .. code-block:: sparql ?x $y NB: pas de distinction entre ``?`` et ``$``, donc ``?x`` et ``$x`` identifient la *même* variable. Triplets ++++++++ * 3 termes (sujet, prédicat, objet) séparés par des espaces et suivis d'un point ``"."``\ : .. code-block:: sparql ?p1 foaf:name "Pierre-Antoine Champin" . * cas particulier : le mot clé ``"a"`` en position de prédicat est un raccourci pour ````\ : .. code-block:: sparql ?p1 a foaf:Person . * le retour à la ligne vaut pour une espace ; la structure est donnée par la ponctuation. Factorisation ------------- * On *peut* « factoriser » plusieurs triplets ayant le même sujet en séparant les couples par un point-virgule ``";"``\ :: <#pa> a foaf:Person ; foaf:givenName "Pierre-Anntoine" ; foaf:surname "Champin" . * On *peut* « factoriser » plusieurs triplets ayant le même sujet et le même prédicat en séparant les objets par une virgule ``","``\ :: <#pa> foaf:phone , . * On peut bien sûr combiner les deux types de factorisation. * On n'est jamais obligé de factoriser, on peut aussi répéter les termes. Nœud muet --------- Lorsqu'un nœud muet n'a qu'un seul arc entrant, au lieu de lui inventer un identifiant local : .. code-block:: sparql <#pa> foaf:know _:quelqun . _:quelqun a foaf:Person ; foaf:name ?n . on peut utiliser la notation ``[]``\ : .. code-block:: sparql <#pa> foaf:knows [ a foaf:Person ; foaf:name ?n ] . .. digraph:: bracketBlankNode graph [ rankdir=LR ] pa [ label="<#pa>" ] bn [ label="" ] Person [ label="foaf:Person" ] n [ label="?n" ] pa -> bn [ label="foaf:knows" ] bn -> Person [ label="rdf:type" ] bn -> n [ label="foaf:name"] Sous-graphe optionel ++++++++++++++++++++ En SPARQL, on peut accepter qu'une partie du graphe ne soit pas satisfaite : .. code-block:: sparql ?p1 a foaf:Person ; foaf:name ?n . OPTIONAL { ?p1 foaf:phone ?tel } Filtres +++++++ En SPARQL, on peut ajouter des contraintes sur les valeurs d'un graphe, avec la clause ``FILTER``. .. code-block:: sparql ?p foaf:age ?a . FILTER (?a >= 18) On peut combiner des conditions avec les opérateurs logiques « et » (``&&``), « ou » (``||``) et « non » (``!``). .. code-block:: sparql FILTER ( 20 <= ?a && ?a < 30 ) Opérations utiles pour les filtres ---------------------------------- * comparaisons : =, !=, <, >, <=, >= * opérateurs arithmétiques : +, -, \*, / * nature d'un nœud : ``isIRI``, ``isBLANK``, ``isLITERAL``, ``isNUMERIC`` * vérifier qu'une variable (utilisée avec ``OPTIONAL``) a bien une valeur : ``Bound`` * recherche de texte : ``REGEX(, )`` Requête SELECT ============== Présentation ++++++++++++ * Similaire au SELECT de SQL : projection sur un sous-ensemble des variables du graphe * Résultat : tableau * une colonne par variable sélectionnée * une ligne par résultat * Structure : ``SELECT WHERE { }`` DISTINCT ++++++++ .. code-block:: sparql SELECT DISTINCT ?sn WHERE { <#pa> foaf:knows ?p. ?p foaf:surname ?sn. } .. digraph:: exempleDistinct graph [ rankdir=LR ] pa [ label="<#pa>" ] john [ label="" ] jane [ label="" ] doe [ shape=rectangle, label="Doe" ] john_name [ shape=rectangle, label="John" ] jane_name [ shape=rectangle, label="Jane" ] pa -> john [ label="foaf:knows" ] pa -> jane [ label="foaf:knows" ] john -> john_name [ label="foaf:givenName" ] john -> doe [ label="foaf:surname" ] jane -> doe [ label="foaf:surname" ] jane -> jane_name [ label="foaf:givenName" ] Sans le ``DISTINCT``, la requête renverra deux fois le résultat ``sn="Doe"``. LIMIT et OFFSET +++++++++++++++ Pour obtenir les 10 premiers résultats : .. code-block:: sparql SELECT ?p WHERE { <#pa> foaf:knows ?p. } LIMIT 10 Pour obtenir les 5 résultats suivants : .. code-block:: sparql SELECT ?p WHERE { <#pa> foaf:knows ?p. } LIMIT 5 OFFSET 10 ORDER BY ++++++++ .. code-block:: sparql SELECT ?p ?n WHERE { <#pa> foaf:knows [ foaf:givenName ?p ; foaf:surname ?n ] } ORDER BY ?n ?p On peut aussi trier par ordre descendant : .. code-block:: sparql SELECT ?name ?age WHERE { <#pa> foaf:knows [ foaf:name ?name ; foaf:age ?age ] } ORDER BY DESC(?age) LIMIT 1 .. note:: l'utilisation du tri *et* de ``LIMIT 1`` permet ici de n'obtenir que la personne la plus vieille que connaît ``<#pa>``. GROUP BY ++++++++ Sert à *aggréger* certaines valeurs avec l'une des fonctions d'aggrégations : ``Count``, ``Sum``, ``Avg``, ``Min``, ``Max``, ``GroupConcat`` et ``Sample``. .. code-block:: sparql SELECT ?p1 (count(?p2) as ?cp2) WHERE { ?p1 foaf:knows ?p2 } GROUP BY ?p1 On peut combiner ``GROUP BY`` avec ``ORDER BY`` et ``LIMIT`` (attention à l'ordre) : .. code-block:: sparql SELECT ?p1 (count(?p2) as ?cp2) WHERE { ?p1 foaf:knows ?p2 } GROUP BY ?p1 ORDER BY DESC(?cp2) LIMIT 3 Autres types de requête ======================= ASK +++ * Sert à demander si un graphe existe ou non dans la base. * Résultat : vrai ou faux * Structure : ``ASK { }`` CONSTRUCT +++++++++ * Sert à construire un graphe à partir des résultat d'un autre * Résultat : un graphe RDF * Structure : ``CONSTRUCT { } WHERE { }`` * Peut jouer un rôle similaire à XSL-T pour RDF Exemple ------- .. code-block:: sparql CONSTRUCT { ?p1 ex:hasMutualFriendWith ?p3 ; foaf:name ?n1 . ?p3 foaf:name ?n3 . } WHERE { ?p1 foaf:knows ?p2 . ?p3 foaf:knows ?p2 . OPTIONAL { ?p1 foaf:name ?n1 } OPTIONAL { ?p3 foaf:name ?n3 } } construit un graphe contenant des arcs ``ex:hasMutualFriendWith`` entre les personnes qui partagent au moins un ami, et copie également les arcs ``foaf:name`` concernant ces personnes, le cas échéant. Résultat de l'exemple ````````````````````` En appliquant l'exemple de ``CONSTRUCT`` ci-dessus au graphe donné en exemple en début de chapitre, on obtient : .. digraph:: simpleDataset graph [ rankdir="LR" margin=0] p3 [ label="c" ] p5 [ label="e" ] n3 [ label="Carol" shape=box ] n5 [ label="Dr Jekyll" shape=box ] n5b [ label="Mr Hyde" shape=box ] p3 -> n3 [ label="foaf:name" ] p5 -> n5 [ label="foaf:name" ] p5 -> n5b [ label="foaf:name" ] # there seem to be a bug with contraint=false, # it reverses the direction of the arc in some cases, # hence the "dir=back" below p3 -> p5 [ label="ex:hasMutualFriendWith" ] p5 -> p3 [ label="ex:hasMutualFriendWith" ] SPARQL Update +++++++++++++ Depuis la version 1.1, possibilité de *modifier* les données. Quelques requêtes utiles ======================== Exploration des types de ressources +++++++++++++++++++++++++++++++++++ .. code-block:: sparql SELECT ?type WHERE { ?o a ?type } GROUP BY ?type ORDER BY DESC(count(?o)) LIMIT 30 Exploration des propriétés liées à un type ++++++++++++++++++++++++++++++++++++++++++ .. code-block:: sparql SELECT DISTINCT ?prop WHERE { ?o a ; ?prop ?val . } LIMIT 30