Как хранить дерево с упорядоченными потомками в 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. |
|-----------+----------------------------+

Обновлено: «Рассчитать длину пути между узлами?» не отвечает на мой вопрос. Здесь обсуждаются неупорядоченные узлы. Мой вопрос конкретно касается упорядоченной коллекции (списка списков) и возврата элементов в исходном порядке.

1) RDF - это набор троек. вам нужны списки RDF. 2) запросы могут работать с путями свойств 3) SPARQL - это нет, язык обхода графа, поэтому он может не работать, если все становится слишком сложным. Тем не менее, не все можно сделать в одном запросе

UninformedUser 10.08.2018 14:34

Возможный дубликат Рассчитать длину пути между узлами?

Jeen Broekstra 11.08.2018 08:55

@JeenBroekstra Я обновил свой вопрос, добавив пояснения. Это больше про stackoverflow.com/questions/17523804.

teksisto 13.08.2018 14:58

Неужели глубина безгранична?

Stanislav Kralin 13.08.2018 22:04

@StanislavKralin Да, глубина произвольна.

teksisto 13.08.2018 22:33

@teksisto, я обновил свой ответ, см. вариант №3. Кстати, какой тройной магазин вы используете?

Stanislav Kralin 03.09.2018 21:08

@StanislavKralin Виртуоз OpenLink

teksisto 05.09.2018 12:19

Хорошо, похоже, что Virtuoso 8 поддерживает правила SPIN: medium.com/virtuoso-blog/…

Stanislav Kralin 05.09.2018 12:50
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
8
454
2

Ответы 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.

Хотя я ценю ваш ответ, я считаю, что упорядочивание по названию - обман. Разве узлы в коллекции еще не заказаны? Действительно ли необходимо вводить новую собственность? Если кто-то переместит какую-то ветку к другому родительскому элементу, будет больно обновлять это свойство.

teksisto 14.08.2018 05:49

@teksisto хорошо, что на самом деле это не было указано в вашем вопросе - мне пришлось самому создавать фактическое моделирование данных. Возможно, вы могли бы проделать какой-нибудь трюк в sparql, например, в stackoverflow.com/questions/17523804, но кажется сложным сделать это одновременно правильным и производительным не только для списка, но и для дерева списков неизвестной глубины. Лично я думаю, что вам лучше решить эту проблему с помощью нескольких запросов, или с помощью API, или с помощью «читерства», о котором я говорил в этом ответе.

Jeen Broekstra 14.08.2018 06:00

Я обновил свой вопрос. Извините, что ввел в заблуждение. Мой вопрос основан на том факте, что даже реляционные базы данных могут получить такую ​​структуру за один запрос, используя вложенный набор. Я думал, что SPARQL может работать с графическими данными лучше, чем реляционные базы данных.

teksisto 14.08.2018 06:27

@teksisto дело не в том, что SPARQL не может его получить - очевидно, может, просто не обязательно в том порядке, в котором вы ожидаете. Проблема в том, что коллекции RDF нелегко пройти по порядку, если вы не используете специальные пользовательские функции. Есть несколько хранилищ троек, в которых для этой цели доступны функции расширения. Однако в ванильном SPARQL это больно.

Jeen Broekstra 14.08.2018 06:34

@teksisto, возможно, Джин Брукстра имеет в виду функции списка Jena ARQ: jena.apache.org/documentation/query/library-propfunc.html

Stanislav Kralin 20.08.2018 09:42

@StanislavKralin Да, я видел эту страницу, но, к сожалению, ни одна из этих функций не имеет отношения к моему вопросу.

teksisto 20.08.2018 14:40

@teksisto, возможно, спросите на community.stardog.com. Stardog имеет множество функций, связанных с графами.

Stanislav Kralin 23.08.2018 09:41

Опция 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.info(label[0]['@value'])
   if (comment) console.info(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

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

Синтаксис черепахи для пустые списки свойств узлов и коллекции требует правильного «порядка появления».

В 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)
    

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