Как хранить дерево с упорядоченными дочерними элементами в RDF? Как обойти такую ​​структуру в SPARQL?

Как сохранить дерево с упорядоченными дочерними элементами в RDF?

Вход:

1. Title 1
   Some text  1.
2. Title 2
2.1. Title 2.1
     Some text under title 2.1.
2.2. Title 2.2
     Some text under title 2.2.

Заголовки могут быть произвольными и не обязательно содержать нумерацию.

Как вернуть все элементы, все еще упорядоченные в одном запросе?

Желаемый результат:

|-----------+----------------------------+
| Title     | Content                    |
|-----------+----------------------------+
| Title 1   | Some text under title 1.   |
| Title 2   |                            |
| Title 2.1 | Some text under title 2.1. |
| Title 2.2 | Some text under title 2.2. |
|-----------+----------------------------+

РЕДАКТИРОВАТЬ: "Рассчитать длину пути между узлами?" не отвечает на мой вопрос. В нем обсуждаются неупорядоченные узлы. Мой вопрос конкретно касается упорядоченной коллекции (списка списков) и возврата элементов в исходном порядке.


person teksisto    schedule 10.08.2018    source источник
comment
1) RDF — это набор троек. вам нужны списки RDF. 2) запросы могут работать с путями к свойствам. 3) SPARQL не является языком обхода графа, поэтому он может дать сбой, если все усложнится. тем не менее, не все может быть сделано в одном запросе   -  person UninformedUser    schedule 10.08.2018
comment
Возможный дубликат Рассчитать длину пути между узлами?   -  person Jeen Broekstra    schedule 11.08.2018
comment
@JeenBroekstra Я обновил свой вопрос с разъяснением. Это больше о stackoverflow.com/questions/17523804.   -  person teksisto    schedule 13.08.2018
comment
Глубина не ограничена?   -  person Stanislav Kralin    schedule 13.08.2018
comment
@StanislavKralin Да, глубина произвольна.   -  person teksisto    schedule 13.08.2018
comment
@teksisto, я обновил свой ответ, см. вариант № 3. Кстати, какой тройной магазин вы используете?   -  person Stanislav Kralin    schedule 03.09.2018
comment
@StanislavKralin Виртуоз OpenLink   -  person teksisto    schedule 05.09.2018
comment
Хорошо, кажется, что Virtuoso 8 поддерживает правила SPIN: d7a060f859ef" rel="nofollow noreferrer">medium.com/virtuoso-blog/   -  person Stanislav Kralin    schedule 05.09.2018


Ответы (2)


Вы можете смоделировать данные своего примера следующим образом:

ex:title1 a ex:Title ;
          rdfs:label "Title 1";
          rdfs:comment "some text under title 1".

ex:title2 a ex:Title ;
          rdfs:label "Title 2";
          rdfs:comment "some text under title 2".


ex:title21 a ex:Title ;
          rdfs:label "Title 2.1";
          rdfs:comment "some text under title 2.1".

ex:title22 a ex:Title ;
          rdfs:label "Title 2.2";
          rdfs:comment "some text under title 2.2".
ex:title2 ex:subtitles (ex:title21 ex:title22).
ex:titleCollection ex:subtitles (ex:title1 ex:title2) .

Тогда запрос для всего по порядку мог бы выполнить очень простое лексическое упорядочение по заголовку:

select ?title ?content 
where {  
    [] ex:subtitles/rdf:rest*/rdf:first [ 
                      rdfs:label ?title ;
                      rdfs:comment ?content ] .
} 
order by ?title

результат:

Evaluating SPARQL query...
+-------------------------------------+-------------------------------------+
| title                               | content                             |
+-------------------------------------+-------------------------------------+
| "Title 1"                           | "some text under title 1"           |
| "Title 2"                           | "some text under title 2"           |
| "Title 2.1"                         | "some text under title 2.1"         |
| "Title 2.2"                         | "some text under title 2.2"         |
+-------------------------------------+-------------------------------------+
4 result(s) (4 ms)

Если вы не хотите полагаться на фактическое свойство title для обеспечения правильного упорядочения, вы, конечно, можете ввести явное свойство упорядочения с иерархической нумерацией и использовать его значение в своем предложении order by.

person Jeen Broekstra    schedule 14.08.2018
comment
Хотя я ценю ваш ответ, я думаю, что упорядочение по названию - это обман. Разве узлы в коллекции еще не упорядочены? Действительно ли необходимо вводить новое свойство? Если кто-то переместит какую-то ветвь к другому родителю, будет сложно обновить это свойство. - person teksisto; 14.08.2018
comment
@teksisto хорошо, что на самом деле это не было указано в вашем вопросе - мне пришлось самому придумать фактическое моделирование данных. Возможно, вы могли бы сделать какой-нибудь трюк в sparql, как в stackoverflow.com/questions/17523804, но кажется сложным получить это как правильно, так и перформанс не только для списка, но и для дерева списков неизвестной глубины. Лично я думаю, что вам лучше решить это с помощью нескольких запросов, или с помощью API, или с помощью читов, которые я описал в этом ответе. - person Jeen Broekstra; 14.08.2018
comment
Я обновил свой вопрос. Извините, что ввел в заблуждение. Мой вопрос основан на том факте, что даже реляционные базы данных могут получить такую ​​структуру в одном запросе, используя вложенный набор. Я думал, что SPARQL лучше справляется с графическими данными, чем реляционные базы данных. - person teksisto; 14.08.2018
comment
@teksisto дело не в том, что SPARQL не может его получить - очевидно, может, просто не обязательно в том порядке, в котором вы ожидаете. Проблема в том, что коллекции RDF нелегко перемещать по порядку, если только вы не используете специальные пользовательские функции. Есть несколько тройных магазинов, в которых для этой цели доступны функции расширения. Однако в ванильном SPARQL это проблема. - person Jeen Broekstra; 14.08.2018
comment
@teksisto, возможно, Джин Брукстра имеет в виду функции списка Jena ARQ: jena.apache.org/ документация/запрос/library-propfunc.html - person Stanislav Kralin; 20.08.2018
comment
@StanislavKralin Да, я видел эту страницу, но, к сожалению, ни одна из этих функций не относится к моему вопросу. - person teksisto; 20.08.2018
comment
@teksisto, возможно, вы могли бы спросить на community.stardog.com. Stardog имеет множество функций, связанных с графами. - person Stanislav Kralin; 23.08.2018

Опция 1

Вы можете сериализовать RDF в сглаженный JSON-LD и написать простая рекурсивная функция в e. грамм. Javascript.

var nquads = `
<http://ex.com/titleCollection> <http://ex.com/subtitles> _:b1 .
_:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> _:b2 .
_:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b3 .
_:b2 <http://www.w3.org/2000/01/rdf-schema#label> "Title 1" .
_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://ex.com/Title> .
_:b2 <http://www.w3.org/2000/01/rdf-schema#comment> "some text under title 1" .
_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> _:b4 .
_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
_:b4 <http://ex.com/subtitles> _:b5 .
_:b4 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://ex.com/Title> .
_:b4 <http://www.w3.org/2000/01/rdf-schema#comment> "some text under title 2" .
_:b4 <http://www.w3.org/2000/01/rdf-schema#label> "Title 2" .
_:b5 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> _:b6 .
_:b5 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b7 .
_:b6 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://ex.com/Title> .
_:b6 <http://www.w3.org/2000/01/rdf-schema#comment> "some text under title 2.1" .
_:b6 <http://www.w3.org/2000/01/rdf-schema#label> "Title 2.1" .
_:b7 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> _:b8 .
_:b7 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
_:b8 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://ex.com/Title> .
_:b8 <http://www.w3.org/2000/01/rdf-schema#comment> "some text under title 2.2" .
_:b8 <http://www.w3.org/2000/01/rdf-schema#label> "Title 2.2" .
`;

jsonld.fromRDF(nquads, {format: 'application/nquads'}, function (err, doc) { 
   print(doc, "http://ex.com/titleCollection") 
});

function print(doc, id) {
   var what = get(doc, id)
   var label = what['http://www.w3.org/2000/01/rdf-schema#label']
   var comment = what['http://www.w3.org/2000/01/rdf-schema#comment']
   var subtitles = what['http://ex.com/subtitles']
   if (label) console.log(label[0]['@value'])
   if (comment) console.log(comment[0]['@value'])
   if (subtitles) {
      for (var i of subtitles[0]['@list']) print(doc, i['@id'])
   }
}

function get(doc, id) {return doc.find((element) => (element['@id'] == id))}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsonld/0.4.12/jsonld.min.js"></script>

Оригинальная Черепаха была:

@prefix ex: <http://ex.com/> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

ex:titleCollection ex:subtitles
    (
        [
        a ex:Title ; rdfs:label "Title 1" ;
        rdfs:comment "some text under title 1" 
        ]
        [
        a ex:Title ; rdfs:label "Title 2" ;
        rdfs:comment "some text under title 2" ;
        ex:subtitles
            (
                [
                a ex:Title ; rdfs:label "Title 2.1" ;
                rdfs:comment "some text under title 2.1" 
                ]
                [
                a ex:Title ; rdfs:label "Title 2.2" ;
                rdfs:comment "some text under title 2.2" 
                ]
            )
        ]
    ) .

Вариант 2

Другой вариант — полагаться на порядок хранения, надеясь, что элементы хранятся в порядке появления.

Синтаксис Turtle для списков свойств пустых узлов и Коллекции заставляет корректировать "порядок появления".

В GraphDB вы могли бы сказать после импорта вышеупомянутой черепахи:

PREFIX ex: <http://ex.com/> 
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX ent: <http://www.ontotext.com/owlim/entity#>

SELECT ?label ?comment {
    ?s a ex:Title ; rdfs:label ?label ; rdfs:comment ?comment
} ORDER BY ent:id(?s)

Вариант 3

Другой вариант — использовать вывод.

  1. Во-первых, давайте придумаем собственный формат для упорядоченных деревьев, т.е. грамм. следующий:

    :title0 a :Node; rdfs:label "Book";
            :down title1.
    :title1 a :Node; rdfs:label "Title 1";
            :down title11;
            :right title2.
    :title2 a :Node; rdfs:label "Title 2";
            :down title21;
            :right title3.
    :title3 a :Node; rdfs:label "Title 3";
            :down title31.
    
  2. Во-вторых, давайте восстановим исходный порядок дерева (и транзитивно закроем его). В SWRL:

    right(?a, ?b) ^ right(?b, ?c) -> right(?a, ?c)
    down(?a, ?b) ^ right(?b, ?c) -> down(?a, ?c)
    down(?a, ?b) ^ down(?b, ?c) -> down(?a, ?c)
    

    Вместо этого вы можете использовать аксиомы OWL или явно утверждать некоторые из выводимых утверждений.

  3. В-третьих, давайте сформулируем правила, определяющие порядок, соответствующий сначала в глубину порядок обхода:

    right(?a, ?b) -> after(?a, ?b)
    down(?a, ?b) -> after(?a, ?b)
    down(?a, ?c) ^ right(?a, ?b) ^ down(?b, ?d) -> after(?c, ?d)
    down(?a, ?c) ^ right(?a, ?b) -> after(?c, ?b)
    right(?a, ?b) ^ down(?b, ?c) -> after(?a, ?c)
    

    Не уверен, что этот набор правил минимален или элегантен...

  4. Теперь ваш запрос SPARQL должен быть:

    SELECT ?s (SAMPLE(?label) AS ?title) (COUNT(?o) AS ?count) {
        ?s a :Node ; rdfs:label ?label .
        OPTIONAL { ?s :after ?o }
    } GROUP BY ?s ORDER BY DESC(?count)
    
person Stanislav Kralin    schedule 16.08.2018