0

假设我的数据对键值映射进行建模,例如,我经营一家高档酒店,并希望跟踪客人每顿饭的订单。我如何确保每顿饭我都得到每位客人的订单(即所有钥匙都在场)并且每位客人我只有一份订单(即所有钥匙都是唯一的)?

让我们开始的示例代码:

形状:

ex:MealShape
    a sh:NodeShape ;
    sh:targetClass ex:Meal ;
    sh:property [
        sh:path ex:orders ;
        sh:minCount 2 ;
        sh:maxCount 2 ;
        sh:node ex:OrderShape ;
    ] .

ex:OrderShape
    a sh:NodeShape ;
    sh:targetClass ex:Order ;
    sh:property [
        sh:path ex:guest ;
        # The guest list! Code maintenance should happen here.
        sh:in ( "James" "Margaret" ) ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
    ] ;
    sh:property [
        sh:path ex:order ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
    ] .

数据:

## Guests
ex:james ex:name "James" .
ex:margaret ex:name "Margaret" .

## Meals
### Valid meal
ex:breakfast
    a ex:Meal ;
    ex:orders [ ex:guest "James" ; ex:order "Eggs" ] ;
    ex:orders [ ex:guest "Margaret" ; ex:order "Cereal" ] .

### DESIRED TO BE invalid meal
### currently does not cause a validation result
ex:lunch
    a ex:Meal ;
    ex:orders [ ex:guest "James" ; ex:order "Salad" ] ;
    # Problem: James placed two orders, Maggie placed zero
    ex:orders [ ex:guest "James" ; ex:order "Burger" ] .

我知道的一种解决方案是对列表中的每个键分别使用qualifiedShape 及其minCount 和maxCount 约束。然而,对于较大的“客人名单”,这变得难以维护。在我的工作中,我有一个大约 40 个键的列表。使用 40 块qualifiedShape 语句,检查列表变得不切实际(而且我已经首先编写了这些语句的生成脚本)。

我已经搜索了文档,但找不到我想要的一种“sh:disjointInScope”或“sh:uniqueFromList”语句(至关重要的是,约束不应强制该值在整个数据图中是唯一的,因为例如 James 可能会出现在几个订单中)。如何在人类可读的 SHACL 代码中获得所需的行为?

4

1 回答 1

1

如果我正确理解了您的特定情况,那么这应该会给您带来违规行为:

ex:MealShape
  sh:property [
      sh:path ( ex:orders ex:guest ) ;
      sh:maxCount 2 ;
      sh:minCount 2 ;
  ] ...

这里的机制是使用路径表达式(SPARQL 表示法中的 ex:orders/ex:guest)来说明每顿饭需要正好有两个不同的客人,这也意味着他们每个人只能是一个订单的一部分. 与 sh:in 结合使用,可确保仅存在允许的键,并且所有键都存在。但是,您需要将 sh:in 列表的长度与 sh:min/max 计数对齐,所以我不确定这将如何管理。

您可能可以在 SHACL-SPARQL 的帮助下进一步概括此模式,例如引入您正在谈论的更高级别的约束组件。

于 2019-05-29T00:28:34.977 回答