Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Saving and reusing the result of a SPARQL query

I am using Jena to query an owl file through Eclipse. I want to do some successive queries and every new query will use the results of the previous query. I want to do it in different ?SELECT and save every time the result of a query in order to use it again in a new query. I dont want to insert the values of the variables by myself but automatically occur from the queries. Any ideas whats a suitable way to achieve this? Thanks in advance

like image 368
user2598911 Avatar asked Oct 04 '22 11:10

user2598911


1 Answers

I think that there are two primary options here:

  1. a. if you're interested in just one QuerySolution from a ResultSet and you're running these queries locally, then you can take the QuerySolution and use it as an initialBindings argument for the QueryExecution, and the values of the variables in the QuerySolution will be used in the second query. This probably only works for local queries (since some the values in the ResultSet could be blank nodes whose values wouldn't make sense in a remote context), and it's only useful if you have a single QuerySolution of interest.
  1. b. The single QuerySolution could also be used to set some values in a ParameterizedSparqlString. In this case, the values are substituted in before you create the actual Query or QueryExecution object, and you could do some other manipulation if you needed as well. You might not be able to reliably run remote queries if some of the results are blank nodes, but you will be able to use this approach with remote endpoints, which you can't do with the initialBindings approach.

  2. The more general solution uses SPARQL 1.1's VALUES to provide the content of the ResultSet in a VALUES block. This is more portable, because any endpoint should be able to handle the VALUES block, and it's more general, because it can handle a bunch of bindings, not just one.

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import com.hp.hpl.jena.query.ParameterizedSparqlString;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.QuerySolutionMap;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.query.ResultSetFormatter;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.sparql.core.Var;
import com.hp.hpl.jena.sparql.engine.binding.Binding;


public class ReuseResults {

    final static String turtleContent = "" +
            "@prefix : <http://example.org/> .\n" +
            "\n" +
            ":alice :hasName \"Alice\" .\n" +
            ":alice :hasAddress \"4222 Clinton Way\" .\n" +
            ":herman :hasName \"Herman\".\n" +
            ":herman :hasAddress \"1313 Mockingbird Lane\" .\n" +
            ":DrWho :hasAddress \"The TARDIS\"" + 
            "";

    // Read the model from the turtle content
    final static Model model = ModelFactory.createDefaultModel() 
            .read( new ByteArrayInputStream( turtleContent.getBytes()), null, "TURTLE" );

    final static String findAlice = "" +
            "prefix : <http://example.org/>\n" +
            "select ?alice where {\n" +
            "  ?alice :hasName \"Alice\" .\n" +
            "}\n" +
            "";

    final static String findAliceAddress = "" +
            "prefix : <http://example.org/>\n" +
            "select ?address where {\n" +
            "  ?alice :hasAddress ?address .\n" +
            "}\n" +
            "";

    public static void useInitialBindingsFromQuerySolution() throws IOException {
        System.out.println( "== useInitialBindingsFromQuerySolution ==" );
        // execute the query that finds a binding for ?alice.  There should be just one 
        // query solution in the result set.
        final ResultSet aliceResults = QueryExecutionFactory.create( findAlice, model ).execSelect();
        final QuerySolution solution = aliceResults.next();
        // Use the single query solution from the result set as initial bindings for
        // the second query (which uses the variable ?alice).
        final ResultSet addressResults = QueryExecutionFactory.create( findAliceAddress, model, solution ).execSelect();
        ResultSetFormatter.out( addressResults );
    }

    public static void useParameterizedSPARQLString() {
        System.out.println( "== useParameterizedSPARQLString ==" );
        // execute the query that finds a (single) binding for ?alice.  Then create
        // a query solution map containing those results.
        final ResultSet aliceResults = QueryExecutionFactory.create( findAlice, model ).execSelect();
        final QuerySolutionMap map = new QuerySolutionMap();
        map.addAll( aliceResults.next() );
        // Create a ParameterizedSparqlString from the findAliceAddress query string (if this
        // approach were taken, findAliceAddress could actually *be* a Param.SparqlString, of
        // course).
        final ParameterizedSparqlString pss = new ParameterizedSparqlString( findAliceAddress );
        System.out.println( pss.toString() );
        pss.setParams( map );
        System.out.println( pss.toString() );
        // execute the query and show the results
        ResultSetFormatter.out( QueryExecutionFactory.create( pss.toString(), model ).execSelect() );
    }

    final static String findNamed = "" +
            "prefix : <http://example.org/>\n" +
            "select ?person where {\n" +
            "  ?person :hasName [] .\n" +
            "}\n" +
            "";

    final static String findPersonAddress = "" +
            "prefix : <http://example.org/>\n" +
            "select ?address where { " +
            "  ?person :hasAddress ?address .\n" +
            "}\n" +
            "";

    public static void useValuesFromResultSet() { 
        System.out.println( "\n== useValuesFromResultSet ==" );
        final ResultSet namedResults = QueryExecutionFactory.create( findNamed, model ).execSelect();
        final QueryExecution qe = QueryExecutionFactory.create( findPersonAddress, model );
        System.out.println( "=== Query Before Adding VALUES ===\n" + qe.getQuery() );
        // Create a list of the variables from the result set
        List<Var> variables = new ArrayList<>();
        for ( final String varName : namedResults.getResultVars() ) {
            variables.add( Var.alloc( varName ));
        }
        // Create a list of the bindings from the result set.
        List<Binding> values = new ArrayList<>();
        while ( namedResults.hasNext() ) {
            values.add( namedResults.nextBinding() );
        }
        // add a values block to the query
        qe.getQuery().setValuesDataBlock(variables, values);
        System.out.println( "\n=== Query After Adding VALUES ===\n" + qe.getQuery() );
        ResultSetFormatter.out( qe.execSelect() );
    }

    public static void main(String[] args) throws IOException {
        useInitialBindingsFromQuerySolution(); // 1.a.
        useParameterizedSPARQLString();        // 1.b.
        useValuesFromResultSet();              // 2.
    }
}

Here's the output that's generated. In the first case, the fact that Alice's address gets selected shows that the value of ?alice carried from the first ResultSet to the initialBindings. In the second case, I've printed the query before and after adding the VALUES clause so that the difference is clear. Note that this will work even if the ResultSet binds multiple variables. The syntax in the case of multiple variables would be VALUES (?v1 ... ?vN) { (value11 ... value1N) ... (valueM1 ... valueMN) }.

== useInitialBindingsFromQuerySolution ==
----------------------
| address            |
======================
| "4222 Clinton Way" |
----------------------

== useParameterizedSPARQLString ==
prefix : <http://example.org/>
select ?address where {
  ?alice :hasAddress ?address .
}

prefix : <http://example.org/>
select ?address where {
  <http://example.org/alice> :hasAddress ?address .
}

----------------------
| address            |
======================
| "4222 Clinton Way" |
----------------------

== useValuesFromResultSet ==
=== Query Before Adding VALUES ===
PREFIX  :     <http://example.org/>
SELECT  ?address
WHERE
  { ?person :hasAddress ?address }

=== Query After Adding VALUES ===
PREFIX  :     <http://example.org/>
SELECT  ?address
WHERE
  { ?person :hasAddress ?address }
VALUES ?person { :herman :alice }

---------------------------
| address                 |
===========================
| "1313 Mockingbird Lane" |
| "4222 Clinton Way"      |
---------------------------
like image 136
Joshua Taylor Avatar answered Oct 07 '22 17:10

Joshua Taylor