Функции для управления коллекциями RDF в SPARQL
Я хотел бы знать, есть ли некоторые функции для управления коллекциями RDF в SPARQL.
Мотивирующая проблема заключается в следующем.
Предположим, у вас есть:
@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-му значению и определить некоторую рекурсивную функцию для вычисления этого выражения. Я думаю, что это невозможно, но, может быть, у кого-то есть хорошее решение.
2 ответа
Нет встроенных модулей, облегчающих формулу…
SPARQL содержит некоторые математические функции для арифметических и агрегатных вычислений. Однако я не знаю каких-либо особенно удобных способов краткого представления математических выражений в SPARQL. Недавно я просматривал статью, в которой обсуждается онтология для представления математических объектов, таких как выражения и определения. Они внедрили систему для их оценки, но я не думаю, что она использовала SPARQL (или, по крайней мере, это было не просто расширение SPARQL).
Венцель, Кен и Хайнер Рейнхардт. " Математические вычисления для приложений со связанными данными с OpenMath ". Совместные материалы 24-го семинара по OpenMath и 7-го семинара по математическим пользовательским интерфейсам (MathUI). 2012.
... но мы все еще можем сделать это дело.
Тем не менее, этот конкретный случай не так уж сложен, поскольку не так сложно работать со списками RDF в SPARQL, а 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
, то любой список l, достижимый из него четным числом повторений (включая 0) rdf:rest/rdf:rest
это список которого rdf:first
является нечетным элементом списка (так как вы начали индексирование с 1). Начиная с л и идти вперед один rdf:rest
мы находимся на чей 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 ]]]] .
}
Результаты (с использованием командной строки 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
Обновить
Я только что понял, что то, что реализовано выше, основано на моем комментарии по вопросу о том, было ли суммирование правильным, потому что оно очень легко упростилось. То есть вышеуказанные средства
(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 ]]]] .
}
Результаты:
$ arq --query query.sparql --data data.n3
------------------------------
| result |
==============================
| 1.666666666666666666666666 |
------------------------------
Конечно, так как выражение может быть упрощено до
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
Результаты:
$ arq --query query.sparql --data data.n3
------------------------------
| result |
==============================
| 1.666666666666666666666666 |
------------------------------
Вы также можете взглянуть на альтернативные способы описания / представления списков в RDF, например, с помощью онтологии упорядоченных списков. Я думаю, что с этой моделью вы можете легко запросить то, что вы хотите;)