Dear Jena community,
we didn't find a way (in the original Jena API 2.10) to completely
detach a result set from the underlying model. It's possible to detach
it from the QueryExecution by using ResultSetFactory.copyResults but the
bindings still point to the TDB backed model.
By this we encountered some issues as we store results sets for a long
time and the read transaction that created the results stays alive (even
if we calls commit or end). Having this read transaction opened leads to
problems when you have many writers after that (stack usage, huge
journal files, ...).
We finally found a way to convert TDB backed result set to a completely
detached ResultSetRewindable. If you find this useful, it's attached below.
Cheers
André
package com.hojoki.core.jena;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.hp.hpl.jena.graph.Graph;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.query.ResultSetRewindable;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.sparql.core.ResultBinding;
import com.hp.hpl.jena.sparql.core.Var;
import com.hp.hpl.jena.sparql.engine.binding.Binding;
import com.hp.hpl.jena.sparql.engine.binding.BindingFactory;
import com.hp.hpl.jena.tdb.store.GraphTDB;
public class ResultsetUtil {
public static boolean isTDBBacked(ResultSet resultSet) {
Model model = resultSet.getResourceModel();
if (model != null) {
Graph g = model.getGraph();
return g instanceof GraphTDB;
}
return false;
}
public static ResultSetRewindable
createDetachedRewindableResultSet(ResultSet resultSet) {
if(resultSet instanceof HojokiResultSet)
return (HojokiResultSet) resultSet;
return isTDBBacked(resultSet) ?
detachAndConvertToRewindable(resultSet) : convertToRewindable(resultSet);
}
private static ResultSetRewindable convertToRewindable(ResultSet
resultSet) {
return toHojokiResultSet(resultSet, false);
}
private static ResultSetRewindable
detachAndConvertToRewindable(ResultSet resultSet) {
return toHojokiResultSet(resultSet, true);
}
public static ResultSetRewindable toHojokiResultSet(ResultSet set,
boolean detachBindings) {
List<String> resultVars = set.getResultVars();
final List<Binding> bindings = new ArrayList<Binding>();
while (set.hasNext()) {
Binding binding = set.nextBinding();
bindings.add(detachBindings ? detachedBinding(binding) : binding);
}
return new HojokiResultSet(resultVars, null, bindings);
}
protected static Binding detachedBinding(Binding binding) {
Iterator<Var> varsIt = binding.vars();
Binding initial = BindingFactory.binding();
while (varsIt.hasNext()) {
Var var = varsIt.next();
initial = BindingFactory.binding(initial, var, binding.get(var));
}
return initial;
}
}
class HojokiResultSet implements ResultSetRewindable {
private List<String> resultVars;
private int rowNumber;
private Model model;
private final List<Binding> bindings;
private Iterator<Binding> iter;
public HojokiResultSet(List<String> resultVars, Model m,
List<Binding> bindings) {
this.bindings = bindings;
this.resultVars = resultVars;
model = m;
reset();
}
/**
* @throws UnsupportedOperationException
* Always thrown.
*/
@Override
public void remove() throws java.lang.UnsupportedOperationException {
throw new UnsupportedOperationException(this.getClass().getName() +
".remove");
}
/**
* Is there another possibility?
*/
@Override
public boolean hasNext() {
return iter.hasNext();
}
@Override
public Binding nextBinding() {
Binding binding = iter.next();
if (binding != null)
rowNumber++;
return binding;
}
/**
* Moves onto the next result possibility. The returned object is
actual the
* binding for this result.
*/
@Override
public QuerySolution nextSolution() {
return new ResultBinding(model, nextBinding());
}
/** Moves onto the next result possibility. */
@Override
public QuerySolution next() {
return nextSolution();
}
/**
* Return the "row number" - a count of the number of possibilities
returned
* so far. Remains valid (as the total number of possibilities) after the
* iterator ends.
*/
@Override
public int getRowNumber() {
return rowNumber;
}
/**
* Get the variable names for the projection
*/
@Override
public List<String> getResultVars() {
return resultVars;
}
public Model getModel() {
return model;
}
@Override
public Model getResourceModel() {
return getModel();
}
@Override
public void reset() {
iter = bindings.iterator();
rowNumber = 0;
}
@Override
public int size() {
return bindings.size();
}
}
--
Dr. André Lanka * 0178 / 134 44 47 * http://dr-lanka.de