Как «вращать» результаты SPARQL в «петле»? - PullRequest
1 голос
/ 15 апреля 2019

Задача

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

Для одного конкретного элемента, такого как город Лейпциг, я могу решить его следующим образомв DBpedia (http://www.dbpedia.org/sparql):

Пример запроса одного элемента

select ?p
{
 ?p dbo:birthPlace dbr:Leipzig.
} limit 3

Вывод одного элемента

http://dbpedia.org/resource/Walter_Ulbricht
http://dbpedia.org/resource/Anita_Berber
http://dbpedia.org/resource/Martin_Benno_Schmidt

НоЯ хочу повернуть вывод и сделать это для всех (или определенного числа) городов:

Требуемый вывод нескольких элементов

City         Person1               Person2                 Person3
dbr:Leipzig  dbr:Walter_Ulbricht       dbr:Anita_Berber    dbr:Martin_Benno_Schmidt
dbr:Bonn     dbr:Anton_Schumacher      dbr:Hermann_Wallich dbr:Fritz_Simrock
dbr:Paris    dbr:Adrien-Marie_Legendre dbr:André_Malraux   dbr:Anselme_Payen
...

Я пытался решить эту проблемусо следующим запросом:

SELECT ?city SAMPLE(?p1) SAMPLE(?p2) SAMPLE(?p3)
{
 ?city ^dbo:birthPlace ?p1,?p2,?p3.
 ?city a dbo:City.

 FILTER(?p1<?p2&&?p2<?p3) # prevent permutations and duplicates

} GROUP BY ?city # only one line per city
LIMIT 10 

Однако я не уверен, является ли это лучшим решением, и у меня есть несколько вопросов:

  • При большем n этот способ написания запросастановится громоздким, есть ли более элегантный вариант (например, с использованием подзапросов)?
  • Дает ли этот запрос все результаты, которые я хочу, т.е. выполняет выборку всей строки или теряет результаты при выборочной выборке каждой переменнойа затем пропустить действительные решения?
  • Если он вернет всерезультаты, которые я получил бы, повторяя одноэлементные запросы, имеет ли он одинаковую эффективность или проходит через большое количество перестановок перед их фильтрацией?Если это не так, есть ли способ написать это более эффективно?

1 Ответ

2 голосов
/ 15 апреля 2019

Вот довольно элегантное и эффективное решение:

  1. В подзапросе используйте GROUP BY с агрегатом group_concat, чтобы объединить URI для всех жителей одного города в одну длинную строку.
  2. Вне подзапроса используйте строковые функции, чтобы разбить длинную строку и взять первые n элементов.

Сделано здесь для первых 100 городов по пять человек в каждом городе:

SELECT ?c ?p1 ?p2 ?p3 ?p4 ?p5 {
    {
        SELECT ?c (group_concat(?p; separator=' ') AS ?list1) {
            {
                SELECT ?c { ?c a dbo:City } LIMIT 100
            }
            OPTIONAL { ?p dbo:birthPlace ?c }
        }
        GROUP BY ?c
    }
    BIND (if(?list1, strAfter(?list1, ' '), undef) AS ?list2)
    BIND (if(?list2, strAfter(?list2, ' '), undef) AS ?list3)
    BIND (if(?list3, strAfter(?list3, ' '), undef) AS ?list4)
    BIND (if(?list4, strAfter(?list4, ' '), undef) AS ?list5)

    BIND (if(?list1, if(contains(?list1, ' '), IRI(strBefore(?list1, ' ')), IRI(?list1)), undef) AS ?p1)
    BIND (if(?list2, if(contains(?list2, ' '), IRI(strBefore(?list2, ' ')), IRI(?list2)), undef) AS ?p2)
    BIND (if(?list3, if(contains(?list3, ' '), IRI(strBefore(?list3, ' ')), IRI(?list3)), undef) AS ?p3)
    BIND (if(?list4, if(contains(?list4, ' '), IRI(strBefore(?list4, ' ')), IRI(?list4)), undef) AS ?p4)
    BIND (if(?list5, if(contains(?list5, ' '), IRI(strBefore(?list5, ' ')), IRI(?list5)), undef) AS ?p5)
}
...