Как мне сохранить дерево с упорядоченными дочерними элементами в 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. | |-----------+----------------------------+
Обновлено: «Рассчитать длину пути между узлами?» не отвечает на мой вопрос. Здесь обсуждаются неупорядоченные узлы. Мой вопрос конкретно касается упорядоченной коллекции (списка списков) и возврата элементов в исходном порядке.
Возможный дубликат Рассчитать длину пути между узлами?
@JeenBroekstra Я обновил свой вопрос, добавив пояснения. Это больше про stackoverflow.com/questions/17523804.
Неужели глубина безгранична?
@StanislavKralin Да, глубина произвольна.
@teksisto, я обновил свой ответ, см. вариант №3. Кстати, какой тройной магазин вы используете?
@StanislavKralin Виртуоз OpenLink
Хорошо, похоже, что Virtuoso 8 поддерживает правила SPIN: medium.com/virtuoso-blog/…
Вы можете смоделировать данные своего примера следующим образом:
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 хорошо, что на самом деле это не было указано в вашем вопросе - мне пришлось самому создавать фактическое моделирование данных. Возможно, вы могли бы проделать какой-нибудь трюк в sparql, например, в stackoverflow.com/questions/17523804, но кажется сложным сделать это одновременно правильным и производительным не только для списка, но и для дерева списков неизвестной глубины. Лично я думаю, что вам лучше решить эту проблему с помощью нескольких запросов, или с помощью API, или с помощью «читерства», о котором я говорил в этом ответе.
Я обновил свой вопрос. Извините, что ввел в заблуждение. Мой вопрос основан на том факте, что даже реляционные базы данных могут получить такую структуру за один запрос, используя вложенный набор. Я думал, что SPARQL может работать с графическими данными лучше, чем реляционные базы данных.
@teksisto дело не в том, что SPARQL не может его получить - очевидно, может, просто не обязательно в том порядке, в котором вы ожидаете. Проблема в том, что коллекции RDF нелегко пройти по порядку, если вы не используете специальные пользовательские функции. Есть несколько хранилищ троек, в которых для этой цели доступны функции расширения. Однако в ванильном SPARQL это больно.
@teksisto, возможно, Джин Брукстра имеет в виду функции списка Jena ARQ: jena.apache.org/documentation/query/library-propfunc.html
@StanislavKralin Да, я видел эту страницу, но, к сожалению, ни одна из этих функций не имеет отношения к моему вопросу.
@teksisto, возможно, спросите на community.stardog.com. Stardog имеет множество функций, связанных с графами.
Вы можете сериализовать 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"
]
)
]
) .
Другой вариант - полагаться на порядок хранения, надеясь, что элементы хранятся в порядке появления.
Синтаксис черепахи для пустые списки свойств узлов и коллекции требует правильного «порядка появления».
В 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)
Другой вариант - использовать логический вывод.
Во-первых, давайте придумаем наш собственный формат для упорядоченных деревьев, например. г. следующий:
: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.
Во-вторых, давайте восстановим исходный порядок дерева (и транзитивно закроем его). В 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 или явно утверждать некоторые из предполагаемых утверждений.
В-третьих, сформулируем правила, определяющие порядок, соответствующий порядку обхода в глубину:
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)
Не уверен, что этот набор правил минимален или элегантен ...
Теперь ваш запрос 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)
1) RDF - это набор троек. вам нужны списки RDF. 2) запросы могут работать с путями свойств 3) SPARQL - это нет, язык обхода графа, поэтому он может не работать, если все становится слишком сложным. Тем не менее, не все можно сделать в одном запросе