Querying with SPARQL¶
Run a Query¶
The RDFLib comes with an implementation of the SPARQL 1.1 Query and SPARQL 1.1 Update query languages.
Queries can be evaluated against a graph with the
rdflib.graph.Graph.query()
method, and updates with
rdflib.graph.Graph.update()
.
The query method returns a rdflib.query.Result
instance. For
SELECT queries, iterating over this returns
rdflib.query.ResultRow
instances, each containing a set of
variable bindings. For CONSTRUCT
/DESCRIBE
queries, iterating over the
result object gives the triples. For ASK
queries, iterating will yield
the single boolean answer, or evaluating the result object in a
boolean-context (i.e. bool(result)
)
For example…
import rdflib
g = rdflib.Graph()
g.parse("http://danbri.org/foaf.rdf#")
knows_query = """
SELECT DISTINCT ?aname ?bname
WHERE {
?a foaf:knows ?b .
?a foaf:name ?aname .
?b foaf:name ?bname .
}"""
qres = g.query(knows_query)
for row in qres:
print(f"{row.aname} knows {row.bname}")
The results are tuples of values in the same order as your SELECT
arguments. Alternatively, the values can be accessed by variable
name, either as attributes, or as items, e.g. row.b
and row["b"]
are
equivalent. The above, given the appropriate data, would print something like:
Timothy Berners-Lee knows Edd Dumbill
Timothy Berners-Lee knows Jennifer Golbeck
Timothy Berners-Lee knows Nicholas Gibbins
...
As an alternative to using SPARQL
s PREFIX
, namespace
bindings can be passed in with the initNs
kwarg, see
Namespaces and Bindings.
Variables can also be pre-bound, using the initBindings
kwarg which can
pass in a dict
of initial bindings. This is particularly
useful for prepared queries, as described below.
Update Queries¶
Update queries are performed just like reading queries but using the rdflib.graph.Graph.update()
method. An
example:
from rdflib import Graph
# Create a Graph, add in some test data
g = Graph()
g.parse(
data="""
<x:> a <c:> .
<y:> a <c:> .
""",
format="turtle"
)
# Select all the things (s) that are of type (rdf:type) c:
qres = g.query("""SELECT ?s WHERE { ?s a <c:> }""")
for row in qres:
print(f"{row.s}")
# prints:
# x:
# y:
# Add in a new triple using SPARQL UPDATE
g.update("""INSERT DATA { <z:> a <c:> }""")
# Select all the things (s) that are of type (rdf:type) c:
qres = g.query("""SELECT ?s WHERE { ?s a <c:> }""")
print("After update:")
for row in qres:
print(f"{row.s}")
# prints:
# x:
# y:
# z:
# Change type of <y:> from <c:> to <d:>
g.update("""
DELETE { <y:> a <c:> }
INSERT { <y:> a <d:> }
WHERE { <y:> a <c:> }
""")
print("After second update:")
qres = g.query("""SELECT ?s ?o WHERE { ?s a ?o }""")
for row in qres:
print(f"{row.s} a {row.o}")
# prints:
# x: a c:
# z: a c:
# y: a d:
Querying a Remote Service¶
The SERVICE
keyword of SPARQL 1.1 can send a query to a remote SPARQL endpoint.
import rdflib
g = rdflib.Graph()
qres = g.query(
"""
SELECT ?s
WHERE {
SERVICE <https://dbpedia.org/sparql> {
?s a ?o .
}
}
LIMIT 3
"""
)
for row in qres:
print(row.s)
This example sends a query to DBPedia’s SPARQL endpoint service so that it can run the query and then send back the result:
<http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.openlinksw.com/schemas/virtcxml#FacetCategoryPattern>
<http://www.w3.org/2001/XMLSchema#anyURI> <http://www.w3.org/2000/01/rdf-schema#Datatype>
<http://www.w3.org/2001/XMLSchema#anyURI> <http://www.w3.org/2000/01/rdf-schema#Datatype>
Prepared Queries¶
RDFLib lets you prepare queries before execution, this saves re-parsing and translating the query into SPARQL Algebra each time.
The method rdflib.plugins.sparql.prepareQuery()
takes a query as
a string and will return a rdflib.plugins.sparql.sparql.Query
object. This can then be passed to the
rdflib.graph.Graph.query()
method.
The initBindings
kwarg can be used to pass in a dict
of
initial bindings:
q = prepareQuery(
"SELECT ?s WHERE { ?person foaf:knows ?s .}",
initNs = { "foaf": FOAF }
)
g = rdflib.Graph()
g.parse("foaf.rdf")
tim = rdflib.URIRef("http://www.w3.org/People/Berners-Lee/card#i")
for row in g.query(q, initBindings={'person': tim}):
print(row)
Custom Evaluation Functions¶
For experts, it is possible to override how bits of SPARQL algebra are
evaluated. By using the setuptools entry-point
rdf.plugins.sparqleval
, or simply adding to an entry to
rdflib.plugins.sparql.CUSTOM_EVALS
, a custom function can be
registered. The function will be called for each algebra component and
may raise NotImplementedError
to indicate that this part should be
handled by the default implementation.
See examples/custom_eval.py