我想实现一个 SPARQL 构造查询,它仅构造图中尚未存在的三元组。
考虑以下示例图:
@prefix crm: <http://www.cidoc-crm.org/cidoc-crm/> .
@prefix sdhss: <https://r11.eu/ns/prosopography/> .
@prefix : <http://www.example.org/> .
:0b5000b1e9 a sdhss:C23 .
:cebbd8cac9 a :E13_sdhss_P36 ;
crm:P140_assigned_attribute_to :0b5000b1e9 ;
crm:P141_assigned [ a crm:E21_Person ] ;
crm:P14_carried_out_by :d4f0bc5a29 ;
crm:P17_was_motivated_by :41cf6794ba .
:b427419ad6 a :E13_sdhss_P35 ;
crm:P140_assigned_attribute_to :0b5000b1e9 ;
crm:P141_assigned [ a sdhss:C24 ] .
:b427419ad7 a :E13_sdhss_P4 ;
crm:P140_assigned_attribute_to :0b5000b1e9 ;
crm:P141_assigned [ a crm:P52_Time-Span] .
为了为 E13_sdhss_P35/P4 实例构造缺失的 P14/P17 三元组,我想出了这样的方法:
prefix : <http://www.example.org/>
prefix crm: <http://www.cidoc-crm.org/cidoc-crm/>
prefix sdhss: <https://r11.eu/ns/prosopography/>
construct {
?e13_a2 crm:P14_carried_out_by ?agent ;
crm:P17_was_motivated_by ?source .
?e13_a3 crm:P14_carried_out_by ?agent ;
crm:P17_was_motivated_by ?source .
}
where {
?c23 a sdhss:C23 .
?e13_a1 a :E13_sdhss_P36 ;
crm:P140_assigned_attribute_to ?c23 ;
crm:P141_assigned [ a crm:E21_Person ] ;
crm:P14_carried_out_by ?agent ;
crm:P17_was_motivated_by ?source .
?e13_a2 a :E13_sdhss_P35 ;
crm:P140_assigned_attribute_to ?c23 ;
crm:P141_assigned [ a sdhss:C24 ] .
?e13_a3 a :E13_sdhss_P4 ;
crm:P140_assigned_attribute_to ?c23 ;
crm:P141_assigned [ a crm:P52_Time-Span ] .
minus {
{?e13_a2 crm:P14_carried_out_by ?agent .}
union
{?e13_a2 crm:P17_was_motivated_by ?source .}
union
{?e13_a3 crm:P14_carried_out_by ?agent .}
union
{?e13_a3 crm:P17_was_motivated_by ?source .}
}
}
这个想法是根据 minus 子句中的模式过滤结果集,并且仅将剩余的绑定传递给构造子句。
这适用于给定的示例图,但是一旦我为
E13_sdhss_P35
或 E13_sdhss_P4
添加 P14/P17 断言,构造查询就会一起返回空。
例如对于使用 P14/P17 断言沿 `E13_sdhss_P35:
进行的以下修改,查询返回空@prefix crm: <http://www.cidoc-crm.org/cidoc-crm/> .
@prefix sdhss: <https://r11.eu/ns/prosopography/> .
@prefix : <http://www.example.org/> .
:0b5000b1e9 a sdhss:C23 .
:cebbd8cac9 a :E13_sdhss_P36 ;
crm:P140_assigned_attribute_to :0b5000b1e9 ;
crm:P141_assigned [ a crm:E21_Person ] ;
crm:P14_carried_out_by :d4f0bc5a29 ;
crm:P17_was_motivated_by :41cf6794ba .
:b427419ad6 a :E13_sdhss_P35 ;
crm:P140_assigned_attribute_to :0b5000b1e9 ;
crm:P141_assigned [ a sdhss:C24 ] ;
crm:P14_carried_out_by :d4f0bc5a29 ;
crm:P17_was_motivated_by :41cf6794ba .
:b427419ad7 a :E13_sdhss_P4 ;
crm:P140_assigned_attribute_to :0b5000b1e9 ;
crm:P141_assigned [ a crm:P52_Time-Span] .
我正在本地 Fuseki 设置上对此进行测试,在实时 GraphDB 实例上,类似的查询似乎工作得很好。
可能的解决方案:
prefix crm: <http://www.cidoc-crm.org/cidoc-crm/>
prefix sdhss: <https://r11.eu/ns/prosopography/>
prefix : <http://www.example.org/>
construct {
?e13_a2_p14 crm:P14_carried_out_by ?agent .
?e13_a2_p17 crm:P17_was_motivated_by ?source .
}
where {
?c23 a sdhss:C23 .
?e13_a1 a :E13_sdhss_P36 ;
crm:P140_assigned_attribute_to ?c23 ;
crm:P141_assigned [ a crm:E21_Person ] ;
crm:P14_carried_out_by ?agent ;
crm:P17_was_motivated_by ?source .
{
?e13_a2_p14 a :E13_sdhss_P35 ;
crm:P140_assigned_attribute_to ?c23 ;
crm:P141_assigned [ a sdhss:C24 ] .
filter not exists { ?e13_a2_p14 crm:P14_carried_out_by ?agent . }
}
union
{
?e13_a2_p17 a :E13_sdhss_P35 ;
crm:P140_assigned_attribute_to ?c23 ;
crm:P141_assigned [ a sdhss:C24 ] .
filter not exists { ?e13_a2_p17 crm:P17_was_motivated_by ?source . }
}
}
早期尝试的问题显然是,一旦 minus/filter 子句匹配,SPARQL 处理器就会从结果集中删除绑定,并且构造子句的机制显然是这样的,只有在所有变量都绑定时才会生成三元组;因此,一旦单个减/过滤子句捕获到某些内容,?e13_a2 就会解除绑定,因此根本不会生成三元组。 这也解释了我之前所做的一个观察,即减号/过滤子句的顺序在之前的尝试中很重要,例如OP减/工会提案。
在应用过滤器约束之前,通过专门命名主题变量(?e13_a2_p14,?e13_a2_p17)可以解决在减号/过滤器匹配上丢失 e13_a2 绑定的问题。