SPARQL 1.2#
This chapter shows how to query the RDF 1.2 annotations introduced in the previous chapter, using SPARQL 1.2 in rudof.
Preliminaries: install and configure rudof#
%pip install -q "pyrudof>=0.3.22"
Note: you may need to restart the kernel to use updated packages.
from pyrudof import Rudof
rudof = Rudof()
The data#
We reuse the example from the RDF 1.2 chapter: Tim Berners-Lee worked at CERN in two separate spells, and received the Princess of Asturias Award in 2002 together with three other people.
This time we write it in the explicit rdf:reifies form rather than with the annotation
syntax, to make plain what the query patterns below will be matching against.
rudof.read_data("""
prefix : <http://example.org/>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
:timbl rdfs:label "Tim Berners Lee" .
_:r rdf:reifies <<( :timbl :employer :CERN )>> ;
:start "1984" ;
:end "1994" .
_:s rdf:reifies <<( :timbl :employer :CERN )>> ;
:start "1980" ;
:end "1980" .
_:t rdf:reifies <<( :timbl :award :PA )>> ;
:time "2002" ;
:togetherWith :vint, :bob, :lawrence .
:vint rdfs:label "Vinton Cerf" .
:bob rdfs:label "Bob Kahn" .
:lawrence rdfs:label "Lawrence Roberts" .
:PA rdfs:label "Princess of Asturias Award" .
:CERN rdfs:label "CERN" .
""")
Matching a triple term#
SPARQL 1.2 extends the query language with the same <<( … )>> notation, and the positions inside a triple term can be variables. So a pattern can
match statements and bind their parts, just as an ordinary pattern matches triples.
The query below finds every reifier of an employment statement and pulls the annotations off it:
rudof.read_query("""
prefix : <http://example.org/>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
SELECT ?person ?employer ?start ?end WHERE {
?r rdf:reifies <<( ?person :employer ?employer )>> ;
:start ?start ;
:end ?end .
}
""")
results = rudof.run_query()
for row in results:
print(f"{row['?person']} at {row['?employer']}: {row['?start']}–{row['?end']}")
<http://example.org/timbl> at <http://example.org/CERN>: "1984"–"1994"
<http://example.org/timbl> at <http://example.org/CERN>: "1980"–"1980"
Both spells at CERN come back as separate solutions, each with its own dates. That is the
payoff: in RDF 1.1 the start and end dates would have been four unrelated triples on
:timbl with no way to pair them up.
Optional annotations#
Annotations are, by their nature, irregular (not every statement carries the same ones).
OPTIONAL is therefore the normal way to read them: bind the annotation if it is there,
and leave the variable unbound if it is not.
rudof.read_query("""
prefix : <http://example.org/>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
SELECT ?person ?award ?time ?togetherPerson WHERE {
?r rdf:reifies <<( ?person :award ?award )>> .
OPTIONAL { ?r :time ?time }
OPTIONAL {
?r :togetherWith ?togetherWith .
?togetherWith rdfs:label ?togetherPerson
}
}
""")
results = rudof.run_query()
print("variables:", results.variables)
for row in results:
print(row)
variables: ['?person', '?award', '?time', '?togetherPerson']
{'?person': '<http://example.org/timbl>', '?award': '<http://example.org/PA>', '?time': '"2002"', '?togetherPerson': '"Bob Kahn"'}
{'?person': '<http://example.org/timbl>', '?award': '<http://example.org/PA>', '?time': '"2002"', '?togetherPerson': '"Vinton Cerf"'}
{'?person': '<http://example.org/timbl>', '?award': '<http://example.org/PA>', '?time': '"2002"', '?togetherPerson': '"Lawrence Roberts"'}
Counting and grouping#
Nothing about triple terms changes the rest of SPARQL, so the usual aggregation applies. Counting how many annotated employment statements exist per person:
rudof.read_query("""
prefix : <http://example.org/>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
SELECT ?person (COUNT(?r) AS ?spells) WHERE {
?r rdf:reifies <<( ?person :employer ?employer )>> .
}
GROUP BY ?person
""")
rudof.run_query()
print(rudof.serialize_query_results())
╭───┬─────────┬──────────────────╮
│ │ ?person │ ?spells │
├───┼─────────┼──────────────────┤
│ 1 │ :timbl │ "2"^^xsd:integer │
╰───┴─────────┴──────────────────╯
References#
SPARQL 1.2 Query Language - the specification.