Here's the full benchmark (tried to attach the source file, but Gmail won't
cooperate for some reason, so it's included below in message body).
Output from my system is below. This is using ARQ 2.8.5, Jena 2.6.3
Note that the bindings query currently incorrectly returns all resources
(x10 because of batching), hence 250000 results not the expected 500.
The "Query all" query returns every resource once, hence 25000. The
assumption is that the client must filter out the 500 results actually
wanted. This filtering isn't included in the timings, which I should
probably fix for it to be a fair comparison.
All others should return 500 results.
Timings given in milliseconds.
++++++++++++++++++++++++++++++
Loading data...OK
Resources = 25000
Triples = 100040
Doing 1 runs, selecting 500 resources...
[250000] Bindings (batches of 50): 4375
[25000] Query all: 390
[500] Naive: 297
[500] Union (no batching): 172
[500] Filter (batches of 50): 47
Finished.
++++++++++
/*
* Created on 12 Oct 2011 by David Allsopp
*/
package com.example;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntModelSpec;
import com.hp.hpl.jena.query.*;
import com.hp.hpl.jena.rdf.model.*;
public class BenchmarkSPARQL
{
/**
* How much data in the model - we create 4 triples for each resource
* */
static final int RESOURCES = 25000;
/**
* We are querying a subset of MAX-MIN resources
* */
static final int MIN = 0;
static final int MAX = 500;
/**
* Repeat each test a few times if necessary to ensure significant
durations
* */
static final int REPS = 1;
/**
* For the strategies that use batching, how many resources to handle in
a
* single query.
* */
static final int BATCHSIZE = 50;
public static void main(String[] args)
{
OntModel ontModel = loadModel();
System.out.println("Doing " + REPS + " runs, selecting " + (MAX -
MIN)
+ " resources...\n");
benchmark(new BindingsStrategy(BATCHSIZE), ontModel);
benchmark(new BruteForceStrategy(), ontModel);
benchmark(new NaiveStrategy(), ontModel);
benchmark(new UnionStrategy(), ontModel);
benchmark(new FilterStrategy(BATCHSIZE), ontModel);
System.out.println("\nFinished.");
}
private static void benchmark(Strategy strategy, OntModel ontModel)
{
long start = System.currentTimeMillis();
for (int j = 0; j < REPS; j++)
{
strategy.run(ontModel);
}
long end = System.currentTimeMillis();
long dur = end - start;
System.out.println(strategy + ": " + dur);
}
static OntModel loadModel()
{
OntModel ontModel =
ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM_RDFS_INF);
System.out.print("Loading data...");
Property lat = ontModel.createProperty("
http://www.example.com/namespace#latitude");
Property lon = ontModel.createProperty("
http://www.example.com/namespace#longitude");
Property comment = ontModel.createProperty("
http://www.example.com/namespace#comment");
for (int i = 0; i < RESOURCES; i++)
{
Resource r = ontModel.createResource("
http://www.example.com/namespace#myresource"
+ i);
ontModel.add(r, lat, Double.toString(90 * Math.random()));
ontModel.add(r, lon, Double.toString(90 * Math.random()));
ontModel.add(r, comment, "Random irrelevant property");
ontModel.add(r, comment, "Another random irrelevant property");
}
System.out.println("OK");
System.out.println("Resources = " + RESOURCES);
System.out.println("Triples = " + ontModel.size());
return ontModel;
}
static int query(String sparqlQuery, OntModel ontModel)
{
Query query = QueryFactory.create(sparqlQuery, Syntax.syntaxARQ);
QueryExecution qexec = QueryExecutionFactory.create(query,
ontModel);
ResultSet jenaResults = qexec.execSelect();
int count = 0;
while (jenaResults.hasNext())
{
QuerySolution qs = jenaResults.nextSolution();
count++;
}
qexec.close();
return count;
}
static abstract class Strategy
{
String name;
public abstract void run(OntModel ontModel);
}
static class NaiveStrategy extends Strategy
{
@Override
public String toString()
{
return "Naive";
}
@Override
public void run(OntModel ontModel)
{
int resultcount = 0;
for (int i = MIN; i < MAX; i++)
{
String resource = "
http://www.example.com/namespace#myresource"
+ i;
String q = "SELECT ?lat ?lon {<"
+ resource
+ "> <http://www.example.com/namespace#latitude>
?lat; <http://www.example.com/namespace#longitude> ?lon}";
resultcount += query(q, ontModel);
}
System.out.print("[" + resultcount + "] ");
}
}
static class FilterStrategy extends Strategy
{
int batchsize;
public FilterStrategy(int batchsize)
{
this.batchsize = batchsize;
}
@Override
public String toString()
{
return "Filter (batches of " + batchsize + ")";
}
@Override
public void run(OntModel ontModel)
{
int batchstart = MIN;
int batchend = MIN + batchsize;
int resultcount = 0;
while (batchstart < MAX)
{
StringBuilder bq = new StringBuilder("prefix ns: <
http://www.example.com/namespace#> select ?x ?lat ?lon {?x ns:latitude ?lat;
ns:longitude ?lon. filter(?x in(");
for (int i = batchstart; i < batchend; i++)
{
String resource = "ns:myresource" + i;
bq.append(resource);
bq.append(",");
}
bq.deleteCharAt(bq.length() - 1);
bq.append("))}");
String bquery = bq.toString();
// System.out.println(bquery);
resultcount += query(bquery, ontModel);
batchstart = batchend;
batchend = batchstart + batchsize;
if (batchend > MAX)
{
batchend = MAX;
}
}
System.out.print("[" + resultcount + "] ");
}
}
static class UnionStrategy extends Strategy
{
@Override
public String toString()
{
return "Union (no batching)";
}
@Override
public void run(OntModel ontModel)
{
StringBuilder bq = new StringBuilder("prefix ns: <
http://www.example.com/namespace#> select ?x ?lat ?lon {");
for (int i = MIN; i < MAX; i++)
{
String resource = "ns:myresource" + i;
bq.append("{?x ns:latitude ?lat; ns:longitude ?lon.
filter(?x="
+ resource + ")");
bq.append("}");
if (i < MAX - 1)
{
bq.append(" UNION \n");
}
}
bq.append(" }");
String query = bq.toString();
// System.out.println(query);
int resultcount = query(query, ontModel);
System.out.print("[" + resultcount + "] ");
}
}
static class BindingsStrategy extends Strategy
{
int batchsize;
public BindingsStrategy(int batchsize)
{
this.batchsize = batchsize;
}
@Override
public String toString()
{
return "Bindings (batches of " + batchsize + ")";
}
@Override
public void run(OntModel ontModel)
{
int batchstart = MIN;
int batchend = MIN + batchsize;
int resultcount = 0;
while (batchstart < MAX)
{
StringBuilder bq = new StringBuilder("prefix ns: <
http://www.example.com/namespace#> select ?x ?lat ?lon {?x ns:latitude ?lat;
ns:longitude ?lon} BINDINGS ?x {");
for (int i = batchstart; i < batchend; i++)
{
String resource = "ns:myresource" + i;
bq.append("(");
bq.append(resource);
bq.append(")");
}
bq.append("}");
String bquery = bq.toString();
// System.out.println(bquery);
int subcount = query(bquery, ontModel);
// System.out.println(subcount);
resultcount += subcount;
batchstart = batchend;
batchend = batchstart + batchsize;
if (batchend > MAX)
{
batchend = MAX;
}
}
System.out.print("[" + resultcount + "] ");
}
}
static class BruteForceStrategy extends Strategy
{
@Override
public String toString()
{
return "Query all";
}
@Override
public void run(OntModel ontModel)
{
String q = "SELECT ?x ?lat ?lon {?x <
http://www.example.com/namespace#latitude> ?lat; <
http://www.example.com/namespace#longitude> ?lon}";
int resultcount = query(q, ontModel);
System.out.print("[" + resultcount + "] ");
}
}
}