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);
}
}
Надеюсь, это поможет, - Дэн