如何在RDF中存储带有有序子项的树?如何在SPARQL中遍历这种结构?

时间:2018-08-10 11:39:33

标签: sparql rdf virtuoso

如何在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. |
|-----------+----------------------------+

编辑:“ Calculate length of path between nodes?”没有回答我的问题。它讨论了无序节点。我的问题特别是关于有序集合(列表列表)和按原始顺序获取元素。

2 个答案:

答案 0 :(得分: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子句中使用该值。

答案 1 :(得分:1)

选项1

您可以将RDF序列化为flattened JSON-LD并在e中编写简单的递归函数。 G。 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

另一种选择是依靠存储顺序,希望按外观顺序存储项目。

blank node property listscollections的Turtle语法强制正确的“出现顺序”。

在GraphDB中,您可以在导入上述Turtle之后说:

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. 首先,让我们发明自己的有序树格式,例如e。 G。以下之一:

    :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. 第三,让我们制定规则来定义与depth-first遍历顺序相对应的顺序:

    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)