========
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