Example 15: Range queries — AllegroGraph Python client 105.1.0 documentation

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