Example 15: Range queriesΒΆ
In many of the previous examples we have used the
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 create a connection:
from franz.openrdf.connect import ag_connect
conn = ag_connect("python-tutorial", create=True, clear=True)
and construct some data:
conn.addData("""
@prefix : <ex://> .
: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
Range
object:
one_to_five = conn.createRange(1, 5)
We can pass the range object to getStatements()
:
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:
<ex://earth>
<ex://mars>
<ex://pluto>
The arguments to createRange()
can be either RDF terms or
regular Python values that will be converted to typed literals
. In our example we used have used values of type int
,
which will be mapped to literals of type
<http://www.w3.org/2001/XMLSchema#integer>
. Range queries will
only match values of exactly the same type. For instance if we add
another triple to our store:
conn.addData("""
@prefix : <ex://> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
:coruscant a :planet ; :moons "4"^^xsd:long .
""")
And then reissue our query:
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:
<ex://earth>
<ex://mars>
<ex://pluto>
Range queries can also be performed with SPARQL, using FILTER
:
conn.executeTupleQuery('''
SELECT ?planet {
?planet <ex://moons> ?moons .
filter (?moons <= 5 && ?moons >= 1)
}''', output=True)
The result is the same as in the previous example.
------------------
| 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 getStatements()
does for range
queries.