我想知道是否有一些函数可以在SPARQL中操作RDF集合.
一个激励性问题如下.
假设你有:
@prefix : <http://example.org#> .
:x1 :value 3 .
:x2 :value 5 .
:x3 :value 6 .
:x4 :value 8 .
:list :values (:x1 :x2 :x3 :x4) .
Run Code Online (Sandbox Code Playgroud)
并且您想要计算以下公式:((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)
}
Run Code Online (Sandbox Code Playgroud)
我想要的是一些方法来访问第N个值并定义某种递归函数来计算该表达式.我认为这是不可能的,但也许有人有一个很好的解决方案.
SPARQL确实包含一些用于算术和聚合计算的数学函数.但是,我不知道在SPARQL中简洁地表示数学表达式的任何特别方便的方法.我最近一直在看一篇论文,讨论用于表示数学对象(如表达式和定义)的本体论.他们实现了一个评估这些的系统,但我认为它不使用SPARQL(或者至少,它不仅仅是SPARQL的简单扩展).
Wenzel,Ken和Heiner Reinhardt." 使用OpenMath进行关联数据应用程序的数学计算." 第24届OpenMath研讨会和第7届数学用户界面研讨会(MathUI)联合会议录.2012.
也就是说,这个特殊情况并不难做到,因为在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 .
Run Code Online (Sandbox Code Playgroud)
用它代表空白节点[],我们可以使它更清晰:
[ rdf:first :x1 ;
rdf:rest [ rdf:first :x2 ;
rdf:rest [ rdf:first :x3 ;
rdf:rest [ rdf:first :x4 ;
rdf:rest rdf:nil ]]]]
Run Code Online (Sandbox Code Playgroud)
一旦列表的头部已被确定,即,与元素rdf:first :x1,那么任何清单升从它到达由偶数重复次数(包括0)的rdf:rest/rdf:rest是其列表rdf:first是列表的奇数元素(因为你开始索引1).从l开始前进rdf:rest,我们在l',它rdf:first是列表中偶数元素.
由于SPARQL 1.1属性路径让我们写入(rdf:rest/rdf:rest)*来表示任何偶数编号的重复rdf:rest,我们可以编写以下查询来绑定:value奇数编号的元素?n和以下偶数编号的元素的值?nPlusOne.SELECT表格中的数学是直截了当的,虽然为了得到N-1,我们实际使用2*COUNT(*)-1,因为行数(每个绑定元素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 ]]]] .
}
Run Code Online (Sandbox Code Playgroud)
结果(使用Jena的命令行ARQ):
$ arq --query query.sparql --data data.n3
------------------------------
| result |
==============================
| 1.333333333333333333333333 |
------------------------------
Run Code Online (Sandbox Code Playgroud)
这是预期的
(5 - 3) + (8 - 6) 2 + 2 4 _
------------------- = ------- = --- = 1.3
(4 - 1) 3 3
Run Code Online (Sandbox Code Playgroud)
我刚刚意识到上面实现的内容是基于我对关于总和是否正确的问题的评论,因为它很容易简化.也就是说,上面的实现
(x2 - x1)+(x4 - x3)+ ... +(xN - xN-1)/(N - 1)
而原始问题要求
(x2 - x1)+(x3 - x2)+ ... +(xN-1 - xN-2)+(xN - xN-1)/(N - 1)
原始甚至更简单,因为对由每个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 ]]]] .
}
Run Code Online (Sandbox Code Playgroud)
结果:
$ arq --query query.sparql --data data.n3
------------------------------
| result |
==============================
| 1.666666666666666666666666 |
------------------------------
Run Code Online (Sandbox Code Playgroud)
当然,因为表达式可以简化为
xN - x1 /(N - 1)
我们也可以使用一个查询,它绑定?x1到列表的?xn第一个元素,最后一个元素,以及?xi列表的每个元素(这样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
Run Code Online (Sandbox Code Playgroud)
结果:
$ arq --query query.sparql --data data.n3
------------------------------
| result |
==============================
| 1.666666666666666666666666 |
------------------------------
Run Code Online (Sandbox Code Playgroud)