When writing queries for an application, whether for an SQL or an RDF data source, its common to end up with a core set of queries that are used time and again. Typically these queries vary only in the values of a few variables.
For example, you might have a query to lookup details of a user (name, homepage, etc) with the variable being the value of the user identifier. The same query is used for all users, you just want to substitute a different value for the variable on each execution.
In Java the JDBC API provides support for this usage using a PreparedStatement object. The ARQ SPARQL query API also provides support for this kind of parameterised query. Here’s some example code that illustrates the technique.
Note: to make use of this technique you’ll have to grab the latest CVS version of ARQ. One of the classes below (QuerySolutionMap
) only got added this weekend.
First up lets create a sample SPARQL query, to extract the name of a foaf:Person
based on the URL of their weblog:
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?name
WHERE {
?x foaf:name ?name.
?x foaf:weblog ?blog.}
You can see that we’ve got two triple patterns in the query. One to match the person’s name, the other to match their weblog URL.
Here’s a code snippet to show how to execute the query and supply the value of the blog
variable at runtime:
//create a Jena model to query against
Model model = ...
//create a node for our variable
RDFNode blog =
model.createResource("http://journal.dajobe.org");
//store the node in a QuerySolutionMap
QuerySolutionMap initialBindings = new QuerySolutionMap();
initialBindings.add("blog", blog);
//here's the query
String queryString =
"PREFIX foaf: <http://xmlns.com/foaf/0.1/>" +
"SELECT ?name " +
"WHERE {" +
"?x foaf:name ?name." +
"?x foaf:weblog ?blog.}";
//create the query object
Query query = QueryFactory.create(queryString);
//execute the query over the model, providing the
//initial bindings for all variables
QueryExecution exec =
QueryExecutionFactory.create(query, model, initialBindings);
ResultSet results = exec.execSelect();
//now format the results...
The code snippet is a fairly typical example of running a SELECT query using ARQ. The key difference is the use of a QuerySolutionMap
. This class implements the QuerySolution
interface, and when used in this context, i.e. as a parameter to the QueryExecutionFactory.create()
method, provides the initial bindings for variables in the query.
The class is basically a map of variable names to RDFNode
objects, so you can add as many of them as you like.
Using this style of query usage means that you can reuse queries, thereby avoiding the need to do string concatentation or API methods to construct the query dynamically.
While I’m at it, here’s another useful tip for folk working with FOAF data. The ARQ function library contains a little function to calculate the sha1sum of a literal or resource value.
Here’s an example query that uses the function:
PREFIX jfn: <java:com.hp.hpl.jena.query.function.library.>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?name
WHERE {
?x foaf:name ?name.
?x foaf:mbox_sha1sum ?sha1.
FILTER ( ?sha1 = jfn:sha1sum(?email) )}
As before we can provide an initial binding that will set the value of the email
variable when the query is executed
//create initial binding for email variable
RDFNode mbox = model.createResource("mailto:leigh@ldodds.com");
QuerySolutionMap map = new QuerySolutionMap();
map.add("email", mbox);
//as before, create and execute query..