SPARQL§

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§

PREFIX foaf: <http://xmlns.com/foaf/0.1/>

SELECT ?n1 ?n2
WHERE {
    ?p1 a <http://xmlns.com/foaf/0.1/Person> .
        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.

PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX : <http://example.com/>

Termes§

IRI en extension (relatif ou absolu) :

<http://xmlns.org/foaf/0.1/Person>
<../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) :

?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 "." :
?p1 foaf:name "Pierre-Antoine Champin" .
  • cas particulier : le mot clé "a" en position de prédicat est un raccourci pour <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> :
?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 <prédicat, objet> 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 <tel:+33-472-44-82-40>, <tel:+33-472-69-21-73>.
    
  • 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 :

<#pa> foaf:know _:quelqun .
_:quelqun a foaf:Person ; foaf:name ?n .

on peut utiliser la notation [] :

<#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 :

?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.

?p foaf:age ?a .
FILTER (?a >= 18)

On peut combiner des conditions avec les opérateurs logiques « et » (&&), « ou » (||) et « non » (!).

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(<variable>, <texte>)

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 <variables> WHERE { <graphe> }

DISTINCT§

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 :

SELECT ?p
WHERE { <#pa> foaf:knows ?p. }
LIMIT 10

Pour obtenir les 5 résultats suivants :

SELECT ?p
WHERE { <#pa> foaf:knows ?p. }
LIMIT 5 OFFSET 10

ORDER BY§

SELECT ?p ?n
WHERE { <#pa> foaf:knows [ foaf:givenName ?p ; foaf:surname ?n ] }
ORDER BY ?n ?p

On peut aussi trier par ordre descendant :

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.

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) :

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 { <graphe> }

CONSTRUCT§

  • Sert à construire un graphe à partir des résultat d’un autre

  • Résultat : un graphe RDF

  • Structure :

    CONSTRUCT { <graphe> } WHERE { <graphe> }

  • Peut jouer un rôle similaire à XSL-T pour RDF

Exemple§

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§

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§

SELECT DISTINCT ?prop
WHERE { ?o a <http://example.org/UnType> ; ?prop ?val . }
LIMIT 30