3

I want to get the latitude and longitude of a place whose name I already know by

PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
PREFIX dbo: <http://dbpedia.org/ontology/>
SELECT * WHERE {
  ?s a dbo:Place .
  ?s geo:lat ?lat .
  ?s geo:long ?long .
} 

where the name of the place (?s) is something like Graves Park. How would one go about implementing the same in Jena where the name of the place might vary?

Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353
Kriss
  • 55
  • 1
  • 6
  • PREFIX geo: PREFIX asd: SELECT ?lati ?longi WHERE { asd:Graves_Park geo:long ?lati. asd:Graves_Park geo:lat ?longi. } gets an empty result – Kriss May 24 '13 at 15:35
  • [Section 3. Denoting or Naming “things”](http://wiki.dbpedia.org/Datasets#h18-4) of “The DBpedia Dataset” says that “Each thing in the DBpedia data set is denoted by a de-referenceable IRI- or URI-based reference of the form http://dbpedia.org/resource/Name, where Name is derived from the URL of the source Wikipedia article.” If you dereference, e.g., http://dbpedia.org/resource/Mount_Monadnock , you get redirected to http://dbpedia.org/page/Mount_Monadnock . The `resource` is the actual thing, and the `page` is just a page that contains information about it. If you scroll to the bottom … – Joshua Taylor May 25 '13 at 13:02
  • … of the page, you'll see links for “Raw data in CSV | RDF (…) | OData (…) | Microdata (…) | JSON-LD”. If you select one of the RDF formats, e.g., [N-Triples](http://dbpedia.org/data/Mount_Monadnock.ntriples), you'll see that all the data is still about the `resource`, not the page. It's sort of like how a biography contains lots of information about a person; the information in the biography (on the `page`) isn't _about_ the biography (the `page`), but is about the person (the `resource`). – Joshua Taylor May 25 '13 at 13:05
  • Thanks a lot for that. yes that makes things a lot clearer now. – Kriss May 26 '13 at 17:28

1 Answers1

3

You can use Jena's ARQ to execute queries against remote SPARQL endpoints. The process is described in ARQ — Querying Remote SPARQL Services.

Using ParameterizedSparqlStrings in SELECT queries

To do this for different places that you might not know until it is time to execute the query, you can use a ParameterizedSparqlString to hold the query and then inject the value(s) once you have them. Here's an example. The query is the one you provided. I put it into a ParameterizedSparqlString, and then used setIri to set ?s to http://dbpedia.org/resource/Mount_Monadnock.

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.ResultSet;
import com.hp.hpl.jena.query.ResultSetFormatter;

public class DBPediaQuery {
    public static void main( String[] args ) {
        final String dbpedia = "http://dbpedia.org/sparql";
        final ParameterizedSparqlString queryString
          = new ParameterizedSparqlString(
                    "PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>"+
                    "PREFIX dbo: <http://dbpedia.org/ontology/>" +
                    "SELECT * WHERE {" +
                    "  ?s a dbo:Place ." +
                    "  ?s geo:lat ?lat ." +
                    "  ?s geo:long ?long ." +
                    "}" );
        queryString.setIri( "?s", "http://dbpedia.org/resource/Mount_Monadnock");
        QueryExecution exec = QueryExecutionFactory.sparqlService( dbpedia, queryString.toString() );
        ResultSet results = exec.execSelect();
        ResultSetFormatter.out( System.out, results );
    }
}

The results printed by this are:

--------------------------------------------------------------------------------------------------------------
| lat                                                 | long                                                 |
==============================================================================================================
| "42.8608"^^<http://www.w3.org/2001/XMLSchema#float> | "-72.1081"^^<http://www.w3.org/2001/XMLSchema#float> |
--------------------------------------------------------------------------------------------------------------

Once you have the ResultSet, you can iterate through the rows of the solution and extract the values. The values here are Literals, and from a Literal you can extract the lexical form (the string value), or the value as the corresponding Java type (in the case of numbers, strings, booleans, &c.). You could do the the following to print the latitude and longitude instead of using the ResultSetFormatter:

while ( results.hasNext() ) {
  QuerySolution solution = results.next();
  Literal latitude = solution.getLiteral( "?lat" );
  Literal longitude = solution.getLiteral( "?long" );

  String sLat = latitude.getLexicalForm();
  String sLon = longitude.getLexicalForm();

  float fLat = latitude.getFloat();
  float fLon = longitude.getFloat();

  System.out.println( "Strings: " + sLat + "," + sLon );
  System.out.println( "Floats: " + fLat + "," + fLon );
}

The output after this change is:

Strings: 42.8608,-72.1081
Floats: 42.8608,-72.1081

Using ParameterizedSparqlStrings in CONSTRUCT queries

Based some of the comments, it may also be useful to use CONSTRUCT queries to save the results from each query, and to aggregate them into a larger model. Here's code that uses a construct query to retrieve the latitude and longitude of Mount Monadnock and Mount Lafayette, and stores them in a single model. (Here we're just using CONSTRUCT WHERE {…}, so the model that is returned is exactly the same as the part of the graph that matched. You can get different results by using CONSTRUCT {…} WHERE {…}.)

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.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;

public class DBPediaQuery {
  public static void main( String[] args ) {
    final String dbpedia = "http://dbpedia.org/sparql";
    final ParameterizedSparqlString queryString
      = new ParameterizedSparqlString(
            "PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>"+
            "PREFIX dbo: <http://dbpedia.org/ontology/>" +
            "CONSTRUCT WHERE {" +
            "  ?s a dbo:Place ." +
            "  ?s geo:lat ?lat ." +
            "  ?s geo:long ?long ." +
            "}" );
    Model allResults = ModelFactory.createDefaultModel();
    for ( String mountain : new String[] { "Mount_Monadnock", "Mount_Lafayette" } ) {
      queryString.setIri( "?s", "http://dbpedia.org/resource/" + mountain );
      QueryExecution exec = QueryExecutionFactory.sparqlService( dbpedia, queryString.toString() );
      Model results = exec.execConstruct();
      allResults.add( results );
    }
    allResults.setNsPrefix( "geo", "http://www.w3.org/2003/01/geo/wgs84_pos#" );
    allResults.setNsPrefix( "dbo", "http://dbpedia.org/ontology/" );
    allResults.setNsPrefix( "dbr", "http://dbpedia.org/resource/" );
    allResults.write( System.out, "N3" );
  }
}

The output shows triples from both queries:

@prefix dbr:     <http://dbpedia.org/resource/> .
@prefix geo:     <http://www.w3.org/2003/01/geo/wgs84_pos#> .
@prefix dbo:     <http://dbpedia.org/ontology/> .

dbr:Mount_Lafayette
      a       dbo:Place ;
      geo:lat "44.1607"^^<http://www.w3.org/2001/XMLSchema#float> ;
      geo:long "-71.6444"^^<http://www.w3.org/2001/XMLSchema#float> .

dbr:Mount_Monadnock
      a       dbo:Place ;
      geo:lat "42.8608"^^<http://www.w3.org/2001/XMLSchema#float> ;
      geo:long "-72.1081"^^<http://www.w3.org/2001/XMLSchema#float> .
Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353
  • what would be an appropriate way to store it in an rdf triple store? im looking at ways of building a triple store but cant get my head around it.. i read that the result set will have the value only for one iteration and after that it will be lost. – Kriss May 24 '13 at 18:48
  • how would one go about say storing the latitude retrieved from the above query to a string? – Kriss May 24 '13 at 18:56
  • @Kriss As to the second comment: I've updated the answer with an example of iterating through the solutions in the result set. – Joshua Taylor May 24 '13 at 21:01
  • @Kriss: As to the first comment: if you want to save the data that you're retrieving, you might use a `CONSTRUCT` query instead of a `SELECT` query, and add the resulting graph to a local model. If this sounds like a suitable option, I can update the answer. – Joshua Taylor May 24 '13 at 21:03
  • I updated with an example a CONSTRUCT query the results of which are aggregated into a single model. – Joshua Taylor May 24 '13 at 21:32
  • Thanks a lot! thats exactly what i was looking for.. although i have one doubt.. i queries Im performing are for pages and not resources. when i try to do it this way for pages i get no output(my first comment has the query string). i have the solution now but could you tell me why that happens? – Kriss May 25 '13 at 10:10
  • @Kriss I took a look and replied to that comment. – Joshua Taylor May 25 '13 at 13:06