Simone Di Cola
Simone Di Cola

Reputation: 87

How to execute a subquery with a different SPARQL endpoint in rdf4j?

I got the following SPARQL query that I am trying to rewrite using the rdf4j sparql builder:

SELECT DISTINCT * {
  SERVICE <http://data.ordnancesurvey.co.uk/datasets/os-linked-data/apis/sparql> {
   SELECT ?ordnanceSurveyRegion
   WHERE {
     VALUES ?outcode {
      "CH"
     }
   ?postcodeArea rdfs:label ?outcode .

   ?postcode spatial:within ?postcodeArea ;
     postcode:district ?ordnanceSurveyRegion .
   }
   LIMIT 1
  }
  ?region owl:sameAs ?ordnanceSurveyRegion ;
   rdfs:label ?regionName .
  FILTER (langMatches(lang(?regionName), "EN"))

  ?report
    ukhpi:refRegion ?region;
    ukhpi:refMonth ?date;
    ukhpi:refPeriodStart ?refPeriodStart ;
    ukhpi:housePriceIndex ?ukhpi ;
    ukhpi:averagePrice ?averagePrice ;
    ukhpi:percentageAnnualChange    ?percentageAnnualChange ;
    ukhpi:percentageChange    ?percentageChange .

} ORDER BY DESC(?date)
LIMIT 1

So far I am able to create the two separate queries, but I have no idea how to put them together. Below the code I have created so far. The queries are correct, the only thing is that from the documentation (https://rdf4j.org/documentation/tutorials/sparqlbuilder/) I cannot see a way to join them together.

  import com.fasterxml.jackson.databind.ObjectMapper;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.rdf4j.federated.FedXFactory;
import org.eclipse.rdf4j.model.vocabulary.OWL;
import org.eclipse.rdf4j.query.resultio.sparqljson.SPARQLResultsJSONWriter;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.util.Repositories;
import org.eclipse.rdf4j.sparqlbuilder.constraint.SparqlFunction;
import org.eclipse.rdf4j.sparqlbuilder.core.Prefix;
import org.eclipse.rdf4j.sparqlbuilder.core.Variable;
import org.eclipse.rdf4j.sparqlbuilder.core.query.Queries;
import org.eclipse.rdf4j.sparqlbuilder.core.query.SelectQuery;
import org.eclipse.rdf4j.sparqlbuilder.graphpattern.GraphPattern;
import org.eclipse.rdf4j.sparqlbuilder.graphpattern.GraphPatterns;
import org.eclipse.rdf4j.sparqlbuilder.graphpattern.SubSelect;
import org.jboss.logging.Logger;

import javax.inject.Inject;

import java.io.ByteArrayOutputStream;

import static org.eclipse.rdf4j.sparqlbuilder.constraint.Expressions.function;
import static org.eclipse.rdf4j.sparqlbuilder.core.SparqlBuilder.*;
import static org.eclipse.rdf4j.sparqlbuilder.rdf.Rdf.*;

public class HousePriceIndex {

    @Inject
    ObjectMapper mapper;

    @Inject
    Logger log;

    @Inject
    @ConfigProperty(name = "land-registry.sparql.endpoint")
    String landRegistrySPARQLEndpoint;

    @Inject
    @ConfigProperty(name = "ordnance-survey.sparql.endpoint")
    String ordnanceSurveySPARQLEndpoint;


    public static void getHousePriceIndexStats(String outcode) {
        //  log.infof("Fetching hpi for %s", outcode);

        Variable averagePrice = var("averagePrice");
        Variable housePriceIndex = var("housePriceIndex");
        Variable percentageChange = var("percentageChange");
        Variable percentageAnnualChange = var("percentageAnnualChange");
        Variable refPeriodStart = var("refPeriodStart");
        Variable ordnanceSurveyRegion = var("ordnanceSurveyRegion");

        Prefix spatial = prefix("spatial", iri("http://data.ordnancesurvey.co.uk/ontology/spatialrelations/"));
        Prefix postcode = prefix("postcode", iri("http://data.ordnancesurvey.co.uk/ontology/postcode/"));
        Prefix owl = prefix(OWL.PREFIX, iri(OWL.NAMESPACE));
        Prefix rdfs = prefix("rdfs", iri("http://www.w3.org/2000/01/rdf-schema#"));
        Prefix ukhpi = prefix("ukhpi", iri("http://landregistry.data.gov.uk/def/ukhpi/"));


        Repository repository = FedXFactory.newFederation()
                .withSparqlEndpoint("http://landregistry.data.gov.uk/landregistry/query")
                .withSparqlEndpoint("http://data.ordnancesurvey.co.uk/datasets/os-linked-data/apis/sparql")
                .create();

        GraphPattern osRegionPattern = var("postcodeArea").has(rdfs.iri("label"), outcode)
                .and(var("postcode").has(spatial.iri("within"), var("postcodeArea"))
                        .andHas(postcode.iri("district"), ordnanceSurveyRegion));


        GraphPattern landRegistryHPIPattern = var("region").has(owl.iri("sameAs"), "ordnanceSurveyRegion")
                .andHas(rdfs.iri("label"), var("regionName"))
                .and((var("report").has(ukhpi.iri("refRegion"), var("region"))
                        .andHas(ukhpi.iri("refMonth"), var("refMonth"))
                        .andHas(ukhpi.iri("refPeriodStart"), refPeriodStart)
                        .andHas(ukhpi.iri("housePriceIndex"), housePriceIndex)
                        .andHas(ukhpi.iri("averagePrice"), averagePrice)
                        .andHas(ukhpi.iri("percentageAnnualChange"), percentageAnnualChange)
                        .andHas(ukhpi.iri("percentageChange"), percentageChange)
                        .filter(function(SparqlFunction.LANGMATCHES, function(SparqlFunction.LANG, var("regionName")), literalOf("EN")))
                ));

        SubSelect osQuery = GraphPatterns
                .select(ordnanceSurveyRegion)
                .where(osRegionPattern)
                .limit(1);


        SelectQuery hpiQuery = Queries.SELECT().distinct()
                .prefix(rdfs, ukhpi, owl, spatial, postcode)
                .select(refPeriodStart, housePriceIndex, percentageAnnualChange, percentageChange, averagePrice)
                .where(osQuery,landRegistryHPIPattern)
                .orderBy(desc(var("refMonth")));



        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        Repositories.tupleQueryNoTransaction(repository, hpiQuery.getQueryString(), new SPARQLResultsJSONWriter(bos));

        System.out.println(bos);

    }

    public static void main(String[] args) {
        getHousePriceIndexStats("CH");
    }
}
   

Can anyone please show me how to achieve that?

Upvotes: 1

Views: 270

Answers (1)

Jeen Broekstra
Jeen Broekstra

Reputation: 22053

An example of creating a subselect via the SparqlBuilder can be found here: https://github.com/eclipse/rdf4j/blob/main/core/sparqlbuilder/src/test/java/org/eclipse/rdf4j/sparqlbuilder/examples/sparql11spec/Section12Test.java

First, change the type of hpiQuery from SelectQuery to SubSelect:

SubSelect hpiQuery = GraphPatterns.select();

Then, you can just pass the subselect object in as another argument for the where() method on the outer select object:

SelectQuery osQuery = Queries.SELECT()
                .prefix(rdfs, spatial, postcode)
                .select(ordnanceSurveyRegion).where(osRegionPattern, hpiQuery).limit(1);

Upvotes: 0

Related Questions