SPARQL — получение узлов с максимальным расстоянием 2 до текущего узла

#sparql #rdf

Вопрос:

Учитывая конкретный узел http://my.org/nodes#n1 в базе данных RDF, я хотел бы получить все узлы, с которыми связаны n1 (с помощью множества предикатов), а затем снова — если возможно — получить все узлы, которые подключены к этим узлам.

Например, приведен следующий график о лицах и с кем они дружат:

 @prefix p: <http://helloworld.org/person#> .
@prefix r: <http://helloworld.org/relation#> .
@prefix l: <http://helloworld.org/location#> .

l:l1 l:city "Sydney" .
l:l2 l:city "Paris" .
l:l3 l:city "New York" .

p:p1 
    p:name "Jack" ;
    p:age 30 ;
    p:livingIn l:l1 .
p:p2 
    p:name "Peter" ;
    p:age 31 ;
    p:livingIn l:l1 .
p:p3 
    p:name "Carol" ;
    p:age 32 ;
    p:livingIn l:l1 .
p:p4 
    p:name "Anna" ;
    p:age 33 ;
    p:livingIn l:l2 .
p:p5 
    p:name "Chris" ;
    p:age 34 ;
    p:livingIn l:l3 .

p:p1 
    r:isFriendOf p:p2 ;
    r:isFriendOf p:p3 .

p:p3 r:isFriendOf p:p4 .

p:p4 r:isFriendOf p:p5 .

 

Я знаю, что между узлами существует только одна связь ( isFriendOf ), и, следовательно, легко запрашивать Jack друзей и их друзей

 PREFIX p: <http://helloworld.org/person#>
PREFIX r: <http://helloworld.org/relation#>

SELECT ?name ?friend ?foaf
WHERE {
    ?p r:isFriendOf ?o .    
    ?p p:name ?name .
    ?o p:name ?friend .
    OPTIONAL { 
        ?o r:isFriendOf ?fo .
        ?fo p:name ?foaf
    }
    FILTER ( ?p = p:p1 )
}
 
Имя друг пенопласт
«Джек» «Питер»
«Джек» «Кэрол» «Анна»

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

 PREFIX id: <http://my.org/graph#>

SELECT ?s ?p ?o ?oo
WHERE { 
    ?s ?p ?o . 
    OPTIONAL { ?o ?p ?oo . } # if an object has connections, get those as well
    FILTER( ?s = id:12345 )  # id:12345 is the node we focus on
}
 

но эта { ?o ?p ?oo } часть мне ничего не дает..

Ответ №1:

Узел, по которому вы выполняете фильтрацию (идентификатор:12345), не существует на опубликованном вами графике.

Запрос, который вы используете, имеет две проблемы: 1) вы ограничиваете свойство между интересующим вас ресурсом (id:12345) и объектом (o), который должен совпадать с объектом между ?o и ?o, 2) запрос неэффективен, так как вы извлекаете полный график, чтобы затем отфильтровать по интересующему узлу. Вместо этого вы могли бы сделать что-то вроде:

 PREFIX id: <http://my.org/graph#>

SELECT ?s ?p ?o ?p1 ?oo
WHERE { 
    id:12345 ?p ?o . 
    OPTIONAL { ?o ?p1 ?oo . } 
}
 

Если вам нужен пример, попробуйте следующее в https://dbpedia.org/sparql

 select ?p ?o ?p1 ?oo where{
<http://dbpedia.org/resource/Madrid> ?p ?o
optional {?o ?p1 ?oo}
}
 

Первый результат выглядит примерно так:

 p   o   p1  oo
http://www.w3.org/1999/02/22-rdf-syntax-ns#type     http://dbpedia.org/ontology/Place   http://www.w3.org/1999/02/22-rdf-syntax-ns#type     http://www.w3.org/2002/07/owl#Class
 

Что имеет смысл: Мадрид-это место, а место-это класс.

Обратите внимание, что при этом отображаются только исходящие ссылки, а не входящие ссылки на интересующий узел. Для этого вам придется сделать что-то вроде:

 select ?s1 ?p1 ?s ?p where{
     ?s ?p <http://dbpedia.org/resource/Madrid>
     optional {?s1 ?p1 ?s}
    }