首先,我不认为你能够完全做你想做的事,但我认为你将能够相当接近。特别是,我认为你提到的最大值约束将特别难以实现。以这种方式处理 SPARQL 中的一组事物通常有点困难。尽管如此,我们还是可以看到我们能做什么。
需要使用的数据
使用我们可以实际使用的一些示例数据来回答此类问题要容易得多。我还从简化问题开始,这样 ABC 只是 A、B 和 C 的交集,以及 C、D 和 E 的 CDE。还没有限制类(它们不会增加太多复杂性,实际上)。出于测试目的(能够确保我们的查询不会返回不需要的值),我还添加了类 F 和 DEF。查看 Turtle 序列化中的数据也更容易,因为它更接近 SPARQL 模式语法。这是简化的本体:
@prefix : <http://stackoverflow.com/q/22396095/1281433/intersections#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
<http://stackoverflow.com/q/22396095/1281433/intersections>
a owl:Ontology .
:A a owl:Class .
:B a owl:Class .
:C a owl:Class .
:D a owl:Class .
:E a owl:Class .
:F a owl:Class .
:ABC a owl:Class ;
owl:equivalentClass [ a owl:Class ;
owl:intersectionOf ( :A :B :C )
] .
:CDE a owl:Class ;
owl:equivalentClass [ a owl:Class ;
owl:intersectionOf ( :C :D :E )
] .
:DEF a owl:Class ;
owl:equivalentClass [ a owl:Class ;
owl:intersectionOf ( :D :E :F )
] .
寻找类的交集
对于相当于交集类的每个类,都有一条从该类到每个相交类的路径。我们可以利用这一事实来找到与包含 A、B 和 C 的交集等效的任何类:
prefix : <http://stackoverflow.com/q/22396095/1281433/intersections#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix xsd: <http://www.w3.org/2001/XMLSchema#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
select distinct ?class where {
?class owl:equivalentClass/
owl:intersectionOf/
rdf:rest*/rdf:first :A, :B, :C .
}
---------
| class |
=========
| :ABC |
---------
不过,这并没有找到 CDE,因为这个查询要求的东西有all指定值。不过,听起来您想要的东西是至少具有某些指定值之一,并且没有非指定值的东西。您可能需要编写两次类列表,但您可以这样做:
prefix : <http://stackoverflow.com/q/22396095/1281433/intersections#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix xsd: <http://www.w3.org/2001/XMLSchema#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
select ?class ?i where {
values ?i { :A :B :C :D :E }
?class owl:equivalentClass/
owl:intersectionOf/
rdf:rest*/rdf:first ?i .
filter not exists {
?class owl:equivalentClass/
owl:intersectionOf/
rdf:rest*/rdf:first ?j .
filter( !(?j in (:A, :B, :C, :D, :E )) )
}
}
order by ?class ?i
--------------
| class | i |
==============
| :ABC | :A |
| :ABC | :B |
| :ABC | :C |
| :CDE | :C |
| :CDE | :D |
| :CDE | :E |
--------------
请注意,DEF 不在结果中,因为虽然它确实具有 D 和 E,但它也具有不属于任何指定类 F 的值。
因为我们过滤掉了每个具有元素的交集类not在输入列表中,我们保证我们的每个交集类keep has only元素are在输入列表中。考虑到这个措辞,我们实际上可以使查询变得更简单:
prefix : <http://stackoverflow.com/q/22396095/1281433/intersections#>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
select ?class ?i where {
# find each ?class that's equivalent to an intersection
?class owl:equivalentClass/owl:intersectionOf ?list .
# and grab the intersecting classes for the results
?list rdf:rest*/rdf:first ?i .
# but filter out any ?class that has an intersecting
# class that's not in the input list.
filter not exists {
?list rdf:rest*/rdf:first ?element .
filter( !(?element in (:A, :B, :C, :D, :E )) )
}
}
--------------
| class | i |
==============
| :ABC | :A |
| :ABC | :B |
| :ABC | :C |
| :CDE | :C |
| :CDE | :D |
| :CDE | :E |
--------------
但这可能效率较低,因为现在您发现every交叉类并过滤掉不合格的类,而不是只找到那些might可以接受,然后过滤掉一些。这有多重要可能取决于您的实际数据。
我认为这回答了你问题的主要部分。要处理限制的交叉点,您只需要注意相关类之间的路径有点不同。您想要匹配的不是列表中的元素,而是匹配owl:someValuesFrom
列表元素的属性,因此路径需要最终的owl:someValuesFrom
:
?class owl:equivalentClass/
owl:intersectionOf/
rdf:rest*/rdf:first/
owl:someValuesFrom ?i .
超越这个
处理其他等价物
如果我查询 A,Z,C,其中 Z 是 B 的等价类,那么这
应该匹配并理想地返回
ABC A
Z
C
这里的查询开始变得有点复杂,但仍然是可以管理的。诀窍在于,而不是选择?i
作为交集列表的简单成员,您需要选择?i
作为交集列表的元素等效的输入列表的成员。然后,过滤out交叉路口也有点复杂。你需要确保有no元素使得有no输入列表中与交集元素等效的元素。将所有这些放在一起,您会得到以下查询:
prefix : <http://stackoverflow.com/q/22396095/1281433/intersections#>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
select ?class ?i where {
?class owl:equivalentClass/
owl:intersectionOf ?list .
?list rdf:rest*/rdf:first/(owl:equivalentClass|^owl:equivalentClass)* ?i .
filter( ?i in (:A, :B, :C, :D, :E ))
filter not exists {
?list rdf:rest*/rdf:first ?element .
filter not exists {
?element (owl:equivalentClass|^owl:equivalentClass)* ?j
filter( ?j in (:A, :B, :C, :D, :E ))
}
}
}
如果添加以下数据
:Z a owl:Class ;
owl:equivalentClass :B .
:AZC a owl:Class ;
owl:equivalentClass [ a owl:Class ;
owl:intersectionOf ( :A :Z :C )
] .
然后你会得到这些结果:
--------------
| class | i |
==============
| :ABC | :A |
| :ABC | :B |
| :ABC | :C |
| :AZC | :A |
| :AZC | :B |
| :AZC | :C |
| :CDE | :C |
| :CDE | :D |
| :CDE | :E |
--------------
这可能不太难(尽管获得最终查询会有点棘手)。重要的是等效类将通过路径关联(owl:equivalentClass|^owl:equivalentClass)*
.
最大结果
其次,结果应该只返回最大匹配;所以如果有
存在一个类 ABCD,我查询 A、B、C、D,它将返回 ABCD
而不是ABC。
如果你能做到的话,这部分可能会相当困难。 SPARQL 实际上并不是为处理此类查询而设计的。计算交集类相交的类数量是很容易的,但是如果你能做到的话,比较这些集合的子集关系将相当困难。