假设我的数据为键值映射建模,例如,我经营一家高档酒店,并希望跟踪每顿饭的客人的订单。如何确保每顿饭都能得到每位客人的订单(即所有键都存在),而每位客人我只能获得一份的订单(即所有键都是唯一的) ?
使我们入门的示例代码:
形状:
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”语句(重要的是,该约束不应强制该值在整个数据图中是唯一的,因为例如詹姆斯可能会以几个顺序出现)。如何在人类可读的SHACL代码中获得所需的行为?
答案 0 :(得分:0)
如果我正确理解了您的特定情况,那么应该给您带来违规之处:
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的帮助下进一步推广此模式,例如介绍您正在讨论的更高级别的约束组件。