Sparql Skos: шире

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

Я сначала "получаю" всех музыкальных исполнителей:

?person rdf:type <http://dbpedia.org/ontology/MusicalArtist> .

Но я хочу ограничить это более широкой категорией Category:American_musicians (через обход skos:broader?): как?

* = хотя вопрос конкретный, я сталкивался с этим квестом много раз, когда хотел выполнить запросы sparql.

4 ответа

Это можно упростить с помощью путей к свойствам в SPARQL 1.1.

SELECT DISTINCT ( ?person )
WHERE
{
  ?person rdf:type dbpedia-owl:MusicalArtist .
  ?person skos:subject  skos:broader* category:American_musicians  .
}

Здесь отображаются все предки, с которыми можно связаться через skos:broader имущество.

Я поражен, что на этот простой вопрос не ответили правильно в течение 3 лет, и как много неопределенности и сомнений распространяют люди.

SELECT * { ?person a dbo:MusicalArtist . filter exists {?person dct:subject/skos:broader* dbc:American_musicians} }

  • исправлено несколько префиксов: dbo вместо длинного dbpedia-owl, dbc вместо category, Эти короткие префиксы встроены в DBpedia
  • исправленный skos:subject (такой опоры не существует) dct:subject
  • исправил запрос путями свойств, он отсутствовал /
  • skos:broader не является переходным, skos:broaderTransitive является. Тем не менее, DBpedia не имеет последнего (без транзитивных рассуждений)
  • заменены DISTINCT который стоит дорого с FILTER EXISTS что намного быстрее. FILTER может остановиться на первой соответствующей подкатегории, которую он находит, в то время как исходный запрос сначала находит все такие подкатегории на художника, а затем отбрасывает их (DISTINCT), сортирует художников по памяти и удаляет дубликаты.

Нет действительно хорошего способа сделать это, но вот подробный способ:

SELECT DISTINCT ( ?person )
WHERE
{
  ?person rdf:type dbpedia-owl:MusicalArtist .
  {
    ?person skos:subject [ skos:broader category:American_musicians ] .
  } UNION {
    ?person skos:subject [ skos:broader [ skos:broader category:American_musicians ] ] .
  } UNION {
    ?person skos:subject [ skos:broader [ skos:broader [ skos:broader category:American_musicians ] ] ] .
  } UNION {
    ?person skos:subject [ skos:broader [ skos:broader [ skos:broader [ skos:broader category:American_musicians ] ] ] ] .
  } UNION {
    ?person skos:subject [ skos:broader [ skos:broader [ skos:broader [ skos:broader [ skos:broader category:American_musicians ] ] ] ] ] .
  } UNION {
    ?person skos:subject [ skos:broader [ skos:broader [ skos:broader [ skos:broader [ skos:broader [ skos:broader category:American_musicians ] ] ] ] ] ] .
  } UNION {
    ?person skos:subject [ skos:broader [ skos:broader [ skos:broader [ skos:broader [ skos:broader [ skos:broader [ skos:broader category:American_musicians ] ] ] ] ] ] ] .
  }
}

Чтобы выяснить, сколько уровней вам нужно, вы можете изменить SELECT DISTINCT на SELECT COUNT DISTINCT и прекратить добавлять уровни, когда отсчет перестанет расти.

Это действительно легко выполнить в neo4j. Альтернативой для выполнения вашей задачи в SPARQL может быть извлечение всего подграфа в "Category:American_musicians" путем итерации с помощью кода в подкатегориях.

Например. псевдокод в Java будет что-то вроде:

String startCategory = "<http://dbpedia.org/resource/Category:American_musicians>";
iterateTraversalFunction(startCategory);

тогда функция обхода будет:

public void iterateTraversalFunction(String startCategory){
     ArrayList<String> artistsURI = // SPARQL query ?person skos:subject startCategory . ?person rdf:type MusicalArtist 

    ArrayList<String> subCategoriesURI = // SPARQL query ?subCat skos startCategory
    // Repeat recursively
   for(String subCatURI: subCategoriesURI){
       iterateTraversalFunction(subCatURI);
   }
}

Надеюсь, это поможет, - Дэн

Другие вопросы по тегам