首先,关于您的 SPARQL 查询的一些注意事项是有序的。*
第一个是关于属性路径中和之间的区别+
,第二个是关于filter
and of的使用values
。然后我们可以看看如何从数据中查询不同类型的子类/超类关系。这里的技巧是,我们正在寻找的一些关系是我们通常会使用 OWL 推理器的关系,但我们正在尝试使用 SPARQL 进行一些 OWL 推理
关于原始查询的几点说明
属性路径,+
以及*
请注意,在您链接到的另一个问题中,属性路径使用*
运算符,这意味着长度为零或更长的路径。长度为零或更多的路径可能非常重要,因为如果您的表单数据中没有明确的三元组
:MyClass owl:equivalentClass :MyClass
你不会得到任何匹配的查询
?myClass owl:equivalentClass+ :MyClass
但你会得到一个结果 ( :MyClass
)
?myClass owl:equivalentClass* :MyClass
实际上,即使owl:equivalentClass
是一个对称属性(即,从a owl:equivalentClass b
我们可以推断出 b owl:equivalentClass a
),三元组可能只存在于数据中的一个方向,所以我们实际上需要
?myClass (owl:equivalentClass|^owl:equivalentClass)* :MyClass
使用values
代替filter
顺便说一句,请注意,在这个查询中,我直接在模式中使用了 IRI;无需filter
像您的原始代码那样:
filter(?s=<http://snomed.info/id/323283001>)
如果您确实想将变量绑定到超类,则使用 更容易values
,如
values ?superclass { <http://snomed.info/id/323283001> }
?subclass (rdfs:subClassOf|owl:equivalentClass)* ?superclass
通过 SPARQL 查询进行 OWL 推理
通常,类之间的关系(例如,子类和超类关系)是您将使用 OWL 推理器为您确定的事情。但是,有些很简单,并且存在于 OWL 公理的 RDF 编码中,您可以使用 SPARQL 查询得出相同的结论。例如,如果您想在基于rdfs:subClassOf
and的层次结构中查找子类关系owl:equivalentClass
,您可以使用如下模式:
?subclass (rdfs:subClassOf|owl:equivalentClass|^owl:equivalentClass)* ?superclass
现在,如下所述,您可能会在使用 Protégé 的 SPARQL 选项卡时遇到一些问题,因此我建议您将|
用法保留为二进制大小写,这样您就可以实际编写,在这种情况下:
?subclass (rdfs:subClassOf|(owl:equivalentClass|^owl:equivalentClass))* ?superclass
现在,您实际查看的数据使用了更复杂的类表达式。当您有以下形式的 OWL 公理时
A subClassOf (B and C)
你实际上是说有一个类A,并且有一个(通常是匿名的)类是一个交集类,它是B和C的交集。你没有公理
A子类B
A子类C
可供您使用,尽管它们在逻辑上确实遵循。你得到的案例实际上也包括一个存在的限制,沿着
A subClassOf (B and C and (p some D))
重要的是要注意 A 的超类是 B、C 和 (p some D)。特别是,A不是p 或 D 的子类。通过一个具体示例,这可能更容易看出:
TiredManWearingHat subClassOf (Man and TiredPerson and (wearing some Hat)
戴帽子的疲惫的人分明是男人,分明是疲倦的人,分明是戴帽子的东西,但他肯定不是戴的(这甚至说不通),他肯定不是帽子。这是一个最小的本体,它具有我们可以使用的结构:
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns="https://stackoverflow.com/q/21092246/1281433/data.owl#">
<owl:Ontology rdf:about="https://stackoverflow.com/q/21092246/1281433/data.owl"/>
<owl:Class rdf:about="https://stackoverflow.com/q/21092246/1281433/data.owl#C"/>
<owl:Class rdf:about="https://stackoverflow.com/q/21092246/1281433/data.owl#B"/>
<owl:Class rdf:about="https://stackoverflow.com/q/21092246/1281433/data.owl#A">
<rdfs:subClassOf>
<owl:Class>
<owl:intersectionOf rdf:parseType="Collection">
<owl:Class rdf:about="https://stackoverflow.com/q/21092246/1281433/data.owl#B"/>
<owl:Class rdf:about="https://stackoverflow.com/q/21092246/1281433/data.owl#C"/>
<owl:Restriction>
<owl:onProperty>
<owl:ObjectProperty rdf:about="https://stackoverflow.com/q/21092246/1281433/data.owl#p"/>
</owl:onProperty>
<owl:someValuesFrom>
<owl:Class rdf:about="https://stackoverflow.com/q/21092246/1281433/data.owl#D"/>
</owl:someValuesFrom>
</owl:Restriction>
</owl:intersectionOf>
</owl:Class>
</rdfs:subClassOf>
</owl:Class>
</rdf:RDF>
我已经写了一个关于检索 OWL 交集类所隐含的超类的答案,描述了如何编写关于交集类的查询,所以我不会在这里再次解释所有内容,但我将包含一个适用于此的查询案子。我展示的结果是我使用 Jena 的命令行 SPARQL 查询工具得到的结果。
prefix : <https://stackoverflow.com/q/21092246/1281433/data.owl#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
select ?superclass where {
:A (rdfs:subClassOf|(owl:intersectionOf/rdf:rest*/rdf:first))* ?superclass .
}
--------------
| superclass |
==============
| :A |
| _:b0 |
| :B |
| :C |
| _:b1 |
--------------
现在,空白节点有匿名交叉类和匿名限制类。如果您不想将它们包含在结果中,则可以很容易地将它们过滤掉:
prefix : <https://stackoverflow.com/q/21092246/1281433/data.owl#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
select ?superclass where {
:A (rdfs:subClassOf|(owl:intersectionOf/rdf:rest*/rdf:first))* ?superclass .
filter(!isBlank(?superclass))
}
--------------
| superclass |
==============
| :A |
| :B |
| :C |
--------------
^owl:equivalentClass|owl:equivalentClass
如果您也想遵循等效类,也 可以添加到该属性路径中。
在 Protégé 中执行此操作
正如我所说,上面的结果是使用 Jena 的命令行工具。你说你想在 Protégé 中做这件事,这让事情变得有点困难,因为它似乎引入了一些问题。我显示的最后一个查询仅在 Protégé 中产生 A 和 B;由于某种原因,它不包括 C:
但是,空白节点的处理要好一些(即,我们可以删除filter
并获得一些有用的输出):
不幸的是,我不确定如何获得与 Jena 在 Protégé 中提供的相同输出,但我正在通过电子邮件发送他们的邮件列表。