【问题标题】:How to execute a subquery with a different SPARQL endpoint in rdf4j?如何在 rdf4j 中使用不同的 SPARQL 端点执行子查询?
【发布时间】:2021-12-31 15:03:38
【问题描述】:

我得到以下 SPARQL 查询,我正在尝试使用 rdf4j sparql 构建器重写:

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

到目前为止,我能够创建两个单独的查询,但我不知道如何将它们放在一起。在我到目前为止创建的代码下方。查询是正确的,唯一的问题是从文档 (https://rdf4j.org/documentation/tutorials/sparqlbuilder/) 中我看不到将它们连接在一起的方法。

  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");
    }
}
   

谁能告诉我如何做到这一点?

【问题讨论】:

    标签: sparql rdf4j


    【解决方案1】:

    可以在此处找到通过 SparqlBuilder 创建子选择的示例:https://github.com/eclipse/rdf4j/blob/main/core/sparqlbuilder/src/test/java/org/eclipse/rdf4j/sparqlbuilder/examples/sparql11spec/Section12Test.java

    首先,将hpiQuery的类型从SelectQuery改为SubSelect

    SubSelect hpiQuery = GraphPatterns.select();
    

    然后,您可以将子选择对象作为外部选择对象上where() 方法的另一个参数传入:

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

    【讨论】:

    • 编译失败。我无法通过 hpiQuery,因为它需要一个 GraphPattern。
    • @simone-di-cola 我已经更新了答案。
    • 非常感谢@Jeen。几小时后试试看。
    • 这里有一个问题:我在哪里以及如何指定内部选择需要由另一个端点解决?换句话说,如何在 sub select 中指定 SERVICE 声明?
    • 我已经用一个工作示例编辑了这个问题。但是输出总是空的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多