SHACL для сравнения значений на двух разных узлах?

Я пытаюсь написать ограничение SHACL для сравнения дат, где начальная дата должна быть меньше или равна конечной дате. Когда даты прикрепляются к одному и тому же узлу с помощью :beginDate а также :endDate предикаты, ограничение прямо вперед:

:StartEndRuleShape a :PropertyShape  ;
  sh:path              :beginDate ;
  sh:lessThanOrEquals  :endDate ;
  sh:message "Begin Date is after End Date." .

Модель реального мира более сложна. На прилагаемой диаграмме обратите внимание, как :AnimalSubjecthasReferenceInterval, ReferenceInterval IRI имеют :ReferenceBegin и :ReferenceEnd которым в свою очередь присваивается значение даты с использованием time:inXSDDate сказуемое. Как я могу применить ограничение в этом случае, чтобы убедиться, что значение ReferenceBegin равно или меньше значения ReferenceEnd? Это случай для использования SHACL-SPARQL или sequencePath? Я не смог найти хороших примеров ни того, ни другого. Ура!

Я протестировал следующий SHACL-SPARQL на данных, которые нарушают ограничение: ReferenceBegin = "2016-12-07", ReferenceEnd = "2016-12-06", но отчет о проверке не обнаруживает нарушения. Если я запускаю SPARQL самостоятельно, он выбирает наблюдение. Есть мысли о том, почему? Я использую Stardog/Stardog Studio и также разместил на своей платформе поддержки пользователей.

@prefix rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix sh:  <http://www.w3.org/ns/shacl#> .
@prefix time: <http://www.w3.org/2006/time#> .
@prefix xsd:  <http://www.w3.org/2001/XMLSchema#> .
@prefix :     <http://foo.bar.org/> .

:IntervalShape a sh:NodeShape ;
 sh:targetClass :ReferenceInterval ;
 sh:sparql [
  a sh:SPARQLConstraint ;
  sh:message "End Date must be greater than or equal to Begin Date";
  sh:prefixes [
    sh:declare [
      sh:prefix "time" ;
      sh:namespace "http://www.w3.org/2006/time#"^^xsd:anyURI ;
    ] 
  ] ;
 sh:select
  """SELECT $this (?beginDate AS ?intervalStart) (?endDate AS ?intervalEnd)
    WHERE {
      $this     :hasReferenceInterval ?interval .
      ?interval :ReferenceBegin       ?beginIRI ;
                :ReferenceEnd         ?endIRI .
      ?beginIRI time:inXSDDate        ?beginDate .
      ?endIRI   time:inXSDDate        ?endDate .
      FILTER  (! (?endDate >= ?beginDate ))
    }""" ;
] .

1 ответ

Решение

Похоже, у вашего ограничения есть две проблемы:

  1. Вы объявляете time префикс в вашем SHACL, но не base префикс. Ты хочешь:

    sh:prefixes [
        sh:declare [
          sh:prefix "time" ;
          sh:namespace "http://www.w3.org/2006/time#"^^xsd:anyURI ;
        ], [
          sh:prefix "" ;
          sh:namespace "http://foo.bar.org/"^^xsd:anyURI ;
        ]
      ] ;
    
  2. Ваш фокусный узел :ReferenceIntervalОднако способ написания вашего запроса, $this будет когда-либо связан только с сущностями, которые :hasReferenceInterval [a :ReferenceInterval], Я переписал запрос так, чтобы ?interval сейчас $this следующее:

    sh:select
      """SELECT $this (?beginDate AS ?intervalStart) (?endDate AS ?intervalEnd)
        WHERE {
          $this     :ReferenceBegin       ?beginIRI ;
                    :ReferenceEnd         ?endIRI .
          ?beginIRI time:inXSDDate        ?beginDate .
          ?endIRI   time:inXSDDate        ?endDate .
          FILTER  (! (?endDate >= ?beginDate ))
        }""" ;
    

    Добавив это ограничение, я смог увидеть нарушение.

Другие вопросы по тегам