9

大家好 rdf/sparql 开发者。这是一个一直困扰我一段时间的问题,但自从 rdf 和 sparql 规范发布以来,似乎没有人准确地回答它。

为了说明这种情况,RDF 定义了几种处理资源多值属性的方法;从创建尽可能多的具有相同 subjet-predicate uris 的三元组到集合或容器。这一切都很好,因为每种模式都有自己的特点。

但从 SPARQL 的角度来看,在我看来,查询这些结构会导致过于复杂的查询(更糟糕的是)无法转录成合理的结果集:您不能使用变量来查询任意长度,而 propertyPath 确实不保持“自然”秩序。

以一种天真的方式,在许多 SELECT 或 ASK 查询中,如果我想查询或过滤容器或列表的值,我大部分时间都不会关心底层模式到底是什么(如果有的话)。例如:

<rdf:Description rdf:about="urn:1">
    <rdfs:label>
        <rdf:Alt>
            <rdf:li xml:lang="fr">Exemple n°1</rdf:li>
            <rdf:li xml:lang="en">Example #1</rdf:li>
        </rdf:Alt>
    </rdfs:label>
    <my:release>
        <rdf:Seq>
            <rdf:li>10.0</rdf:li>
            <rdf:li>2.4</rdf:li>
            <rdf:li>1.1.2</rdf:li>
            <rdf:li>0.9</rdf:li>
        </rdf:Seq>
    </my:release>
</rdf:Description>

<rdf:Description rdf:about="urn:2">
    <rdfs:label xml:lang="en">Example #2</rdfs:label>
</rdf:Description>

显然,我希望这两个资源都能回答查询:

SELECT ?res WHERE { ?res rdfs:label ?label . FILTER ( contains(?label, 'Example'@en) }

我也希望查询:

SELECT ?ver WHERE { <urn:1> my:release ?ver }

以原始顺序返回 rdf:Seq 元素(或任何 rdf:Alt)(对于其他模式,是否保留原始顺序无关紧要,所以为什么不保留它呢?) - 除非明确指定通过 ORDER BY 子句。

当然,有必要保持与旧方法的兼容性,所以也许有可能用新的运算符扩展 propertyPath 语法?

我觉得它会大大简化日常 SPARQL 用例。

这对你有意义吗?此外,你有什么理由不尝试实施这个吗?

编辑更正了示例的 urn:2 rdfs:label 值不正确

4

2 回答 2

8

我意识到这个问题已经有了答案,但是如果你使用 RDF 列表而不是其他类型的 RDF 容器,那么值得看看你可以在这里做什么。首先,您在 Turtle 中提供的数据(在提供命名空间声明之后)是:

@prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#> .
@prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix my:    <https://stackoverflow.com/q/16223095/1281433/> .

<urn:2>  rdfs:label  "Example #2"@en .

<urn:1>  rdfs:label  [ a       rdf:Alt ;
                       rdf:_1  "Exemple n°1"@fr ;
                       rdf:_2  "Example #1"@en
                     ] ;
        my:release  [ a       rdf:Seq ;
                      rdf:_1  "10.0" ;
                      rdf:_2  "2.4" ;
                      rdf:_3  "1.1.2" ;
                      rdf:_4  "0.9"
                    ] .

属性rdf:_n是这里的难点,因为它们是唯一为序列中的元素提供任何真实顺序的东西。(虽然它仍然使用属性,但 alt 并没有真正的重要序列rdf:_n。)如果您使用使rdf:_n属性成为可选的 SPARQL 属性路径,则可以获得所有三个标签:

prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#>
prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

select ?x ?label where {
  ?x rdfs:label/(rdf:_1|rdf:_2|rdf:_3)* ?label
  filter( isLiteral( ?label ))
}
------------------------------
| x       | label            |
==============================
| <urn:1> | "Exemple n°1"@fr |
| <urn:1> | "Example #1"@en  |
| <urn:2> | "Example #2"@en  |
------------------------------

让我们看看您可以用 RDF 列表做什么。如果您使用列表,那么您的数据是这样的:

@prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#> .
@prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix my:    <https://stackoverflow.com/q/16223095/1281433/> .

<urn:2>  rdfs:label  "Example #2"@en .

<urn:1>  rdfs:label  ( "Exemple n°1"@fr "Example #1"@en ) ;
        my:release  ( "10.0" "2.4" "1.1.2" "0.9" ) .

现在您可以相对轻松地获取标签:

prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#>
prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

select ?x ?label where {
  ?x rdfs:label/(rdf:rest*/rdf:first)* ?label
  filter( isLiteral( ?label ))
}
------------------------------
| x       | label            |
==============================
| <urn:1> | "Exemple n°1"@fr |
| <urn:1> | "Example #1"@en  |
| <urn:2> | "Example #2"@en  |
------------------------------

如果你想要标签列表中标签的位置,你甚至可以得到它,尽管它使查询更复杂一点:

prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#>
prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

select ?x ?label (count(?mid)-1 as ?position) where {
  ?x rdfs:label ?y .
  ?y rdf:rest* ?mid . ?mid rdf:rest*/rdf:first? ?label .
  filter(isLiteral(?label))
}
group by ?x ?label
-----------------------------------------
| x       | label            | position |
=========================================
| <urn:1> | "Exemple n°1"@fr | 0        |
| <urn:1> | "Example #1"@en  | 1        |
| <urn:2> | "Example #2"@en  | 0        |
-----------------------------------------

这使用了Is it possible to get the position of an element in an RDF Collection in SPARQL 中的技术吗?计算列表中作为 的对象的每个值的位置rdfs:label,从 开始0并分配0给不在列表中的元素。

于 2014-03-05T23:17:19.637 回答
5

RDF 为集合和容器定义了一个词汇表,但就包含它们的图应如何解释而言,它们没有特殊含义。它们不适用于表示多值属性,也并不真正适合表示多值属性。

一般来说,说:

:A :predicate [ a rdf:Alt ; rdf:_1 :B ; rdf:_2 :C ] .

不等于

:A :predicate :B , :C .

假设谓词是owl:sameAs:

:A owl:sameAs [ a rdf:Alt ; rdf:_1 :B ; rdf:_2 :C ] .

上面说 :A 命名一个包含:B 和 :C 的个体,而:

:A owl:sameAs :B , :C .

表示 :A、:B 和 :C 是同一个人。

SPARQL 与容器和集合无关(除了 rdf:List 的语法简写)。如果您想要一种更方便的方式来处理集合,包括Jenardflib在内的许多 RDF API都为它们提供了一流的表示。

附录

对多值属性建模的方法——也就是说,对“Example n°1”@fr 和“Example #1”@en 都是 urn:1 的标签进行建模——是简单地陈述两个事实:

<rdf:Description rdf:about="urn:1">
    <rdfs:label xml:lang="fr">Exemple n°1</rdfs:label>
    <rdfs:label xml:lang="en">Example #1</rdfs:label>
    ...
</rdf:Description>

和查询:

SELECT ?res WHERE { ?res rdfs:label ?label . FILTER ( contains(?label, 'Example'@en) ) }

将匹配 <urn:1> 和 <urn:2> 的英文标签。

对于 my:release 属性,您有一个多值属性并对其值进行排序,这有点棘手。您可以定义一个新属性(例如)my:releases,其值为 rdf:List 或 rdf:Seq。my:release 给出直接关系,而 my:releases 给出指定显式排序的间接关系。使用推理存储和适当的规则,您只需提供后者。不幸的是,这并没有使在 SPARQL 中使用排序变得更容易。

在 SPARQL 和非推理存储中更容易使用的方法是使版本本身成为具有定义排序属性的对象:

  <rdf:Description rdf:about="urn:1">
    <rdfs:label xml:lang="fr">Exemple n&#xB0;1</rdfs:label>
    <rdfs:label xml:lang="en">Example #1</rdfs:label>
    <my:release>
      <my:Release>
        <dc:issued rdf:datatype="&xsd;date">2008-10-10/dc:issued>
        <my:version>10.0</my:version>
      </my:Release>
    </my:release>
    <my:release>
      <my:Release>
        <my:version>2.4</my:version>
        <dc:issued rdf:datatype="&xsd;date">2007-05-01</dc:issued>
      </my:Release>
    </my:release>
    ...
  </rdf:Description>

在上面,日期可用于对结果进行排序,因为不再有明确的顺序。查询稍微复杂一点:

SELECT ?ver 
WHERE { <urn:1> my:release [ my:version ?ver ; dc:issued ?date ] }
ORDER BY ?date
于 2013-04-26T04:36:28.727 回答