.. _example15:
Example 15: Range queries
-------------------------
In many of the previous examples we have used the
:meth:`getStatements` method to find all triples conforming to a given
pattern. The patterns we have used so far matched each triple
component against a single value. It is possible to use more complex
patterns that can match a range of values for each component. To
illustrate this let us first construct some data:
.. testcode:: example15
conn = connect()
conn.addData("""
@prefix : .
:mercury a :planet ; :moons 0 .
:venus a :planet ; :moons 0 .
:earth a :planet ; :moons 1 .
:mars a :planet ; :moons 2 .
:jupiter a :planet ; :moons 67 .
:saturn a :planet ; :moons 62 .
:uranus a :planet ; :moons 27 .
:neptune a :planet ; :moons 14 .
:pluto a :dwarf_planet ; :moons 5 .
""")
Suppose that we want to locate all planets that have at least one, but
no more than five moons. To issue such a query we need to create a
:class:`.Range` object:
.. testcode:: example15
one_to_five = conn.createRange(1, 5)
We can pass the range object to :meth:`getStatements`:
.. testcode:: example15
moons = conn.createURI('ex://moons')
with conn.getStatements(
None, moons, one_to_five) as result:
for statement in result:
print(statement.getSubject())
This will find two planets and one dwarf planet, as expected:
.. testoutput:: example15
:options: +SORT
The arguments to :meth:`createRange` can be either RDF terms or
regular Python values that will be converted to typed :class:`literals
`. In our example we used have used values of type ``int``,
which will be mapped to literals of type
````. Range queries will
only match values of exactly the same type. For instance if we add
another triple to our store:
.. testcode:: example15
conn.addData("""
@prefix : .
@prefix xsd: .
:coruscant a :planet ; :moons "4"^^xsd:long .
""")
And then reissue our query:
.. testcode:: example15
with conn.getStatements(
None, moons, one_to_five) as result:
for statement in result:
print(statement.getSubject())
we will find that the result has not changed:
.. testoutput:: example15
:options: +SORT
Range queries can also be performed with SPARQL, using ``FILTER``:
.. testcode:: example15
conn.executeTupleQuery('''
SELECT ?planet {
?planet ?moons .
filter (?moons <= 5 && ?moons >= 1)
}''', output=True)
The result is the same as in the previous example.
.. testoutput:: example15
:options: +SORT
------------------
| planet |
==================
| ex://coruscant |
| ex://earth |
| ex://mars |
| ex://pluto |
------------------
When the filter expression is a simple set of inequalities, as it is
in this case, the query engine will use indices to optimize the query
execution, similaraly to the way :meth:`getStatements` does for range
queries.