我想知道是否有一些函数可以在 SPARQL 中操作 RDF 集合。

一个激励问题如下。

假设你有:

@prefix : <http://example.org#> .
:x1 :value 3 .
:x2 :value 5 .
:x3 :value 6 .
:x4 :value 8 .

:list :values (:x1 :x2 :x3 :x4) .

并且您要计算以下公式:((Xn - Xn-1) + ... (X2 - X1))/(N - 1)

有什么通用的计算方法吗?

到目前为止,我只能针对一组固定的值计算它。例如,对于 4 个值,我可以使用以下查询:
prefix : <http://example.org#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

SELECT ?r {
 ?list :values ?ls .
 ?ls rdf:first ?x1 .
 ?ls rdf:rest/rdf:first ?x2 .
 ?ls rdf:rest/rdf:rest/rdf:first ?x3 .
 ?ls rdf:rest/rdf:rest/rdf:rest/rdf:first ?x4 .
 ?x1 :value ?v1 .
 ?x2 :value ?v2 .
 ?x3 :value ?v3 .
 ?x4 :value ?v4 .
 BIND ( ((?v4 - ?v3) + (?v3 - ?v2) + (?v2 - ?v1)) / 3 as ?r)
}

我想要的是某种方式来访问第 N 个值并定义某种递归函数来计算该表达式。我认为这是不可能的,但也许有人有一个很好的解决方案。

最佳答案

没有使公式更容易的内置插件......

SPARQL 确实包含一些用于算术和聚合计算的数学函数。但是,我不知道有什么特别方便的方法可以在 SPARQL 中简洁地表示数学表达式。我最近一直在看一篇论文,该论文讨论了用于表示表达式和定义等数学对象的本体。他们实现了一个系统来评估这些,但我认为它没有使用 SPARQL(或者至少,它不仅仅是 SPARQL 的简单扩展)。



……但我们仍然可以做这种情况。

也就是说,这种特殊情况并不难做,因为在 SPARQL 中使用 RDF 列表并不太难,而且 SPARQL 包括此表达式所需的数学函数。首先,介绍一下 RDF 列表表示,这将使解决方案更容易理解。 (如果您已经熟悉这一点,您可以跳过下一两段。)

RDF 列表是链表,每个列表通过 rdf:first 属性与它的第一个元素相关,通过 rdf:rest 与列表的其余部分相关。所以方便的符号 (:x1 :x2 :x3 :x4) 实际上是以下的简写:

_:l1 rdf:first :x1 ; rdf:rest _:l2 .
_:l2 rdf:first :x2 ; rdf:rest _:l3 .
_:l3 rdf:first :x3 ; rdf:rest _:l4 .
_:l3 rdf:first :x4 ; rdf:rest rdf:nil .

[] 表示空白节点,我们可以更清楚一点:
[ rdf:first :x1 ;
  rdf:rest [ rdf:first :x2 ;
             rdf:rest [ rdf:first :x3 ;
                        rdf:rest [ rdf:first :x4 ;
                                   rdf:rest rdf:nil ]]]]

一旦确定了列表的头部,即具有 rdf:first :x1 的元素,那么通过 rdf:rest/rdf:rest 的偶数次重复(包括 0)可以从它到达的任何列表 l 是一个列表,其 rdf:first 是列表的奇数元素(因为您从 1) 开始索引。从 l 开始,向前推进一个 rdf:rest ,我们在 l' 处,其 rdf:first 是列表中的偶数元素。

由于 SPARQL 1.1 属性路径让我们编写 (rdf:rest/rdf:rest)* 来表示 rdf:rest 的任何偶数重复,我们可以编写以下查询,将 :value 的奇数元素的 ?n 和以下偶数元素的值绑定(bind)到 ?nPlusOneSELECT 形式的数学很简单,虽然为了得到 N-1,我们实际上使用 2*COUNT(*)-1 ,因为行数(每行绑定(bind)元素 n 和 n+1)是 N/2。
prefix : <http://example.org#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

SELECT ( SUM(?nPlusOne-?n)/(2*COUNT(*)-1) as ?result) {
 ?list :values [ (rdf:rest/rdf:rest)* [ rdf:first [ :value ?n ] ;
                                        rdf:rest  [ rdf:first [ :value ?nPlusOne ]]]] .
}

结果(使用 Jena 的命令行 ARQ):
$ arq --query query.sparql --data data.n3
------------------------------
| result                     |
==============================
| 1.333333333333333333333333 |
------------------------------

这是预期的,因为
 (5 - 3) + (8 - 6)     2 + 2     4      _
------------------- = ------- = --- = 1.3
      (4 - 1)            3       3

更新

我刚刚意识到上面实现的内容是基于我对求和是否正确的问题的评论,因为它很容易简化。也就是说,上面的实现



而最初的问题要求



原始的更简单,因为这些对由原始列表的每个 rdf:rest 标识,而不仅仅是偶数的重复。使用与上述相同的方法,此查询可以表示为:
prefix : <http://example.org#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

SELECT ( SUM(?nPlusOne-?n)/COUNT(*) as ?result) {
 ?list :values [ rdf:rest* [ rdf:first [ :value ?n ] ;
                             rdf:rest  [ rdf:first [ :value ?nPlusOne ]]]] .
}

结果:
$ arq --query query.sparql --data data.n3
------------------------------
| result                     |
==============================
| 1.666666666666666666666666 |
------------------------------

当然,由于表达式可以简化为



我们也可以使用一个查询,将 ?x1 绑定(bind)到列表的第一个元素,?xn 绑定(bind)到最后一个元素,?xi 绑定(bind)到列表的每个元素(这样 COUNT(?xi) (以及 COUNT(*) )是列表中的项目数) :
prefix : <http://example.org#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

SELECT (((?xn-?x1)/(COUNT(?xi)-1)) as ?result) WHERE {
 ?list :values [ rdf:rest*/rdf:first [ :value ?xi ] ;
                 rdf:first [ :value ?x1 ] ;
                 rdf:rest* [ rdf:first [ :value ?xn ] ;
                             rdf:rest  rdf:nil ]] .
}
GROUP BY ?x1 ?xn

结果:
$ arq --query query.sparql --data data.n3
------------------------------
| result                     |
==============================
| 1.666666666666666666666666 |
------------------------------

关于rdf - 在 SPARQL 中操作 RDF 集合的函数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17312774/

10-13 01:14