Reputation: 87
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
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