Как запросить онтологию SUMO с помощью SPARQL

Я использую онтологию SUMO, которую хочу запросить с помощью SPARQL. Типичная запись в SUMO, например, для города, выглядит так:

<owl:Thing rdf:ID="MadridSpain">
 <rdfs:isDefinedBy rdf:resource="http://www.ontologyportal.org/SUMO.owl"/>
 <rdf:type rdf:resource="#City"/>
 <owl:comment xml:lang="en">The City of Madrid in Spain.</owl:comment>
 <geographicSubregion rdf:resource="#Spain" />
 <externalImage rdf:datatype="xsd:anyURI">[...]</externalImage>
 <rdfs:label xml:lang="en">madrid spain</rdfs:label>
</owl:Thing>

Если я хочу получить все города из онтологии, я использую этот пример запроса (который отлично работает):

String prefix = "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> "
              + "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>";
String rdq = prefix + "SELECT ?N ?O WHERE {?N rdf:type <http://www.ontologyportal.or/SUMO.owl#City>}";

Моя проблема начинается, когда я хочу отфильтровать результаты. Предположим, мне нужны только все города, которые являются географическим субрегионом Испании. Сначала я попытался решить эту проблему, проанализировав все результаты в Java и Jena, на что уходит огромное количество времени (5-10 секунд на каждый результат, всего ~ 10000 результатов).

Query myQuery = QueryFactory.create(rdq);
QueryExecution qexec = QueryExecutionFactory.create(myQuery, owlModel);
try {
 ResultSet results = qexec.execSelect();
 for (; results.hasNext();) {
  QuerySolution sol = results.nextSolution();
  Resource res = sol.getResource("N");
  StmtIterator it = res.listProperties();

  while(it.hasNext()){
   Statement state = it.next();
   //Doing some filtering
   System.out.println("predicate: " + state.getPredicate().toString());
   System.out.println("subject: " + state.getSubject().toString());
   System.out.println("object: " + state.getObject().toString());
  }
 }
}catch (Exception e) {
 e.printStackTrace();
 System.err.println("Query Error " + e.getMessage());
}

Конечно, это не очень эффективно, и должен существовать более простой способ с использованием правильного запроса. Но на данный момент я застрял в определении такого запроса. Я пробовал следующие, но ни один из них не работает.

SELECT ?N ?O WHERE { ?N rdf:type <http://www.ontologyportal.org/SUMO.owl#City> . 
 { SELECT ?N WHERE { (rdf:type ?b rdf:statement) .
 (rdf:Predicate ?b <http://www.ontologyportal.org/SUMO.owl#geographicSubregion>) .
 (rdf:Object ?b <http://www.ontologyportal.org/SUMO.owl#Spain>) } } }

SELECT ?N ?O WHERE { (rdf:statement ?b) .
 (rdf:Predicate ?b <http://www.ontologyportal.org/SUMO.owl#geographicSubregion>) . 
 (rdf:Object ?b <http://www.ontologyportal.org/SUMO.owl#Spain>) . }";

Есть ли у кого-нибудь идея, как создать запрос, который получает все города в стране?


person FredFloete    schedule 17.09.2013    source источник
comment
Вы добились в этом прогресса? Несколько лет назад я кратко познакомился с SUMO и не знал, что есть перевод OWL, поэтому было интересно посмотреть. Если ответ пока не помог, с какими еще проблемами вы столкнулись?   -  person Joshua Taylor    schedule 18.09.2013
comment
Ваше решение отлично работает и +1 за отличный ответ.   -  person FredFloete    schedule 20.09.2013
comment
Рад помочь! Как я уже сказал, я не знал о переводе SUMO в OWL, так что для меня это была хорошая новость. Спасибо, что спросили об этом!   -  person Joshua Taylor    schedule 20.09.2013


Ответы (1)


Я взял представленный вами RDF, чтобы создать минимальный RDF-файл, который я мог бы запросить:

<rdf:RDF xmlns="http://www.ontologyportal.org/SUMO.owl#"
         xml:base="http://www.ontologyportal.org/SUMO.owl"
         xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
         xmlns:owl="http://www.w3.org/2002/07/owl#"
         xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
  <owl:Thing rdf:ID="MadridSpain">
    <rdfs:isDefinedBy rdf:resource="http://www.ontologyportal.org/SUMO.owl"/>
    <rdf:type rdf:resource="#City"/>
    <owl:comment xml:lang="en">The City of Madrid in Spain.</owl:comment>
    <geographicSubregion rdf:resource="#Spain" />
    <externalImage rdf:datatype="xsd:anyURI">[...]</externalImage>
    <rdfs:label xml:lang="en">madrid spain</rdfs:label>
  </owl:Thing>
</rdf:RDF>

SPARQL - это язык запросов для сопоставления данных в графах RDF. Ребра в графе RDF - это тройки, простые утверждения формы объект предиката субъекта. Вы играли против одиночной тройки.

?N rdf:type <http://www.ontologyportal.org/SUMO.owl#City>

Ваш запрос, как он есть, будет легче написать, если вы определите префикс для sumo:, поэтому мы получим (также переименовав ?N в ?city):

prefix sumo: <http://www.ontologyportal.org/SUMO.owl#>
select ?city where { 
  ?city rdf:type sumo:City .
}

Как вы видели, при этом выбираются все города. Теперь вам просто нужно сопоставить дополнительную тройку, поэтому мы просто добавляем ее в запрос:

prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
prefix sumo: <http://www.ontologyportal.org/SUMO.owl#>
select ?city where { 
  ?city rdf:type sumo:City .
  ?city sumo:geographicSubregion sumo:Spain .
}

Чтобы это выглядело лучше, можно использовать два сокращения. Во-первых, в SPARQL rdf:type можно записать как a, потому что это очень распространено (и тогда нам тоже не нужно будет определять префикс). Во-вторых, если у вас есть несколько троек с одним и тем же предметом, вы можете перечислить части объекта-предиката, разделенные точкой с запятой. В итоге мы получаем

prefix sumo: <http://www.ontologyportal.org/SUMO.owl#>
select ?city where { 
  ?city a sumo:City ;
        sumo:geographicSubregion sumo:Spain .
}

Когда я запускаю это против RDF выше, используя инструменты командной строки Jena, я получаю следующие результаты:

$ arq --data sumo.rdf --query query.sparql
--------------------
| city             |
====================
| sumo:MadridSpain |
--------------------

Почему другие запросы не работали

Что вы пытались сделать в таких вещах

(rdf:type ?b rdf:statement) .
(rdf:Predicate ?b <http://www.ontologyportal.org/SUMO.owl#geographicSubregion>) .
(rdf:Object ?b <http://www.ontologyportal.org/SUMO.owl#Spain>)

использовал словарь реификации RDF. Во-первых, синтаксис должен быть таким:

?b a rdf:Statement ;
   rdf:subject ?city ;
   rdf:predicate sumo:geographicSubregion ;
   rdf:object sumo:Spain .

чтобы соответствовать овеществленной тройке формы, необходимой для ответа на ваш запрос. Однако этот запрос требует, чтобы на графике указанной формы было четыре тройки, а их нет в модели. То, что на графике присутствует тройка, не означает, что она существует в овеществленной версии. (В конце концов, поскольку все тройки, которые используются для материализации первой тройки, также должны быть реифицируются, а затем и те, и так далее.) SPARQL позволяет запрашивать только те тройки, которые на самом деле находятся в данных.

person Joshua Taylor    schedule 17.09.2013
comment
Спасибо за отличный комментарий. Ваше решение отлично работает. Спасибо, что приложили все усилия, чтобы объяснить мои ошибки. - person FredFloete; 20.09.2013