.. _example13:
Example 13: SPARQL query forms
------------------------------
SPARQL provides alternatives to the standard SELECT query. This
example exercises these alternatives to show how AllegroGraph Server
and the Python client handle them.
We'll need some sample data to illustrate all the query types. Our
dataset will contain information about rulers of 17th century England.
.. testcode:: example13
conn = connect()
conn.addData("""
@prefix : .
@prefix xsd: .
:james_i :reigned_from "1603-03-24"^^xsd:date ;
:reigned_to "1625-03-27"^^xsd:date .
:charles_i :reigned_from "1625-03-27"^^xsd:date ;
:reigned_to "1649-01-30"^^xsd:date ;
:child_of :james_i .
:charles_ii :reigned_from "1649-01-30"^^xsd:date ;
:reigned_to "1685-02-06"^^xsd:date ;
:child_of :charles_i .
:james_ii :reigned_from "1685-02-06"^^xsd:date ;
:reigned_to "1688-12-11"^^xsd:date ;
:child_of :charles_i .
:mary_ii :reigned_from "1689-02-13"^^xsd:date ;
:reigned_to "1694-12-28"^^xsd:date ;
:child_of :james_ii .
:william_iii :reigned_from "1672-07-04"^^xsd:date ;
:reigned_to "1702-03-08"^^xsd:date .
:anne :reigned_from "1707-05-01"^^xsd:date ;
:reigned_to "1714-08-01"^^xsd:date ;
:child_of :james_ii .
""")
``SELECT``
~~~~~~~~~~
This kind of query returns a sequence of tuples, binding variables to
matching elements of a search pattern. ``SELECT`` queries are created
using :meth:`prepareTupleQuery` and return results of type
:class:`.TupleQueryResult`. Query result can also be serialized in a
supported :class:`.TupleFormat` - in previous examples we used
``output=True`` and relied on the default ``TupleFormat.TABLE``.
Here's a sample query which locates all rulers whose grandchildren
inherited the crown:
.. testcode:: example13
conn.setNamespace('', 'ex://')
query = conn.prepareTupleQuery(query="""
SELECT DISTINCT ?name WHERE {
?grandchild :child_of/:child_of ?name .
} ORDER BY ?name """)
with query.evaluate() as result:
for bindings in result:
print(bindings.getValue('name'))
Two names are returned:
.. testoutput:: example13
We can also serialize the output instead of processing the result
object. This time let us reverse the query and ask for rulers whose
grandparents are also in the dataset:
.. testcode:: example13
from franz.openrdf.rio.tupleformat import TupleFormat
query = conn.prepareTupleQuery(query="""
SELECT DISTINCT ?name WHERE {
?name :child_of/:child_of ?grandparent .
} ORDER BY ?name """)
query.evaluate(output=True, output_format=TupleFormat.CSV)
We get four results, serialized as CSV:
.. testoutput:: example13
name
"ex://anne"
"ex://charles_ii"
"ex://james_ii"
"ex://mary_ii"
``ASK``
~~~~~~~
The ``ASK`` query returns a Boolean, depending on whether the triple
pattern matched any triples. Queries of this type are created using
:meth:`prepareBooleanQuery`.
Let's check if there were any co-regencies in the time period
described by our dataset:
.. testcode:: example13
query = conn.prepareBooleanQuery(query="""
ASK { ?ruler1 :reigned_from ?r1from ;
:reigned_to ?r1to .
?ruler2 :reigned_from ?r2from ;
:reigned_to ?r2to .
FILTER (?ruler1 != ?ruler2 &&
?r1from >= ?r2from &&
?r1from < ?r2to)
}""")
print(query.evaluate())
There was one (William and Mary):
.. testoutput:: example13
True
``CONSTRUCT``
~~~~~~~~~~~~~
The ``CONSTRUCT`` query creates triples by substantiating provided
templates with values resulting from matching a pattern. Queries of
this kind are created using :meth:`prepareGraphQuery` and return a
:class:`.RepositoryResult` - which is an iterator over the constructed
triples.
.. note::
Executing a ``CONSTRUCT`` query will *not* add any triples to the
store. To insert the data we have to iterate over the result and
add each triple using :meth:`addStatement` (or use an ``INSERT``
query).
Let us consider a query that calculates a ``:sibling_of``
relationship:
.. testcode:: example13
print('Size before: {0}'.format(conn.size()))
query = conn.prepareGraphQuery(query="""
CONSTRUCT {
?person1 :sibling_of ?person2 .
} WHERE {
?person1 :child_of ?parent .
?person2 :child_of ?parent .
filter (?person1 != ?person2) .
}""")
for stmt in query.evaluate():
print('{0} <-> {1}'.format(stmt.getSubject(),
stmt.getObject()))
print('Size after: {0}'.format(conn.size()))
The returned object is an iterator over |Statement| objects. We can
also see that no data has been added to the repository.
.. testoutput:: example13
Size before: 19
<->
<->
<->
<->
Size after: 19
We can also serialize the result using any of the supported
:class:`RDFFormats <.RDFFormat>`:
.. testcode:: example13
from franz.openrdf.rio.rdfformat import RDFFormat
query.evaluate(output=True,
output_format=RDFFormat.NTRIPLES)
Here we use the `N-Triples`_ format. This happens to be the default,
so we could have omitted the ``output_format`` argument.
.. testoutput:: example13
.
.
.
.
``DESCRIBE``
~~~~~~~~~~~~
The ``DESCRIBE`` query returns triples that 'describe' a given set of
resources. Such queries are created using :meth:`prepareGraphQuery`
and return :class:`.RepositoryResult` objects.
The set of resources to be processed is specified by a query
pattern. The SPARQL standard does not say what triples constitute a
'description' of a particular resource. AllegroGraph will return the
`Concise Bounded Description`_ of the queried resources.
Let's use a ``DESCRIBE`` query to see what data do we have regarding
the children of Charles I:
.. testcode:: example13
query = conn.prepareGraphQuery(query="""
DESCRIBE ?child WHERE {
?child :child_of :charles_i
}""")
for stmt in query.evaluate():
print(stmt)
In this case AllegroGraph will simply return all triples with subject
in the specified set:
.. testoutput:: example13
:options: +SORT
(, , "1649-01-30"^^)
(, , "1685-02-06"^^)
(, , )
(, , "1685-02-06"^^)
(, , "1688-12-11"^^)
(, , )
DESCRIBE queries can be useful for exploring a dataset and learning
what properties a certain object might have. The results of such
queries can be serialized to any supported :class:`.RDFFormat`:
.. testcode:: example13
query.evaluate(output=True,
output_format=RDFFormat.NTRIPLES)
.. testoutput:: example13
:options: +SORT
"1649-01-30"^^ .
"1685-02-06"^^ .
.
"1685-02-06"^^ .
"1688-12-11"^^ .
.
.. _Concise Bounded Description: https://www.w3.org/Submission/CBD/