关于 UNION 和 FILTER NOT EXISTS in SPARQL (OpenRDF 2.8.0)
About UNION and FILTER NOT EXISTS in SPARQL (OpenRDF 2.8.0)
几年前我学习了一些语义技术,包括RDF和SPARQL,然后有一段时间没有机会使用它们。现在我开始了一个使用 OpenRDF 2.8.0 作为语义存储的新项目,我正在恢复我的知识,尽管我有一些遗忘的东西需要恢复。
特别是,在过去的几天里,我在正确理解 SPARQL 中的 FILTER NOT EXIST 结构方面遇到了一些麻烦。
问题:我有一个从 DbTune.org(音乐本体)导入的语义存储。 mo:MusicArtist
,作为 mo:Track
的 foaf:maker
,可以出现在四种情况下(我只列出相关陈述):
<http://dbtune.org/musicbrainz/resource/artist/013c8e5b-d72a-4cd3-8dee-6c64d6125823> a mo:MusicArtist ;
vocab:artist_type "1"^^xs:short ;
rdfs:label "Edvard Grieg" .
<http://dbtune.org/musicbrainz/resource/artist/032df978-9130-490e-8857-0c9ef231fae8> a mo:MusicArtist ;
vocab:artist_type "2"^^xs:short ;
rel:collaboratesWith <http://dbtune.org/musicbrainz/resource/artist/3db5dfb1-1b91-4038-8268-ae04d15b6a3e> , <http://dbtune.org/musicbrainz/resource/artist/d78afc01-f918-440c-89fc-9d546a3ba4ac> ;
rdfs:label "Doris Day & Howard Keel".
<http://dbtune.org/musicbrainz/resource/artist/1645f335-2367-427d-8e2d-ad206946a8eb> a mo:MusicArtist ;
vocab:artist_type "2"^^xs:short ;
rdfs:label "Pat Metheny & Anna Maria Jopek".
<http://dbtune.org/musicbrainz/resource/artist/12822d4f-4607-4f1d-ab16-d6bacc27cafe> a mo:MusicArtist ;
rdfs:label "René Marie".
据我了解,vocab:artist_type
对于单个艺术家(示例 #1)是 1
,对于合作组(示例 #2 和 #3)是 2
。在这种情况下,可能有几个 rel:collaboratesWith
语句指向组或协作的单个成员的描述(示例 #2)。在某些情况下,缺少 vocab:artist_type
语句(示例 #4)。
现在我想尽可能将所有艺术家提取为单个实体。我的意思是,我不想检索示例 #2,因为我将分别获得 "Doris Day" 和 "Howard Keel"。我必须检索示例 #3 "Pat Metheny & Anna Maria Jopek",因为我无能为力。当然我也想检索"René Marie".
我已经用这个 SPARQL 以令人满意的方式解决了这个问题:
SELECT *
WHERE
{
?artist a mo:MusicArtist.
?artist rdfs:label ?label.
MINUS
{
?artist vocab:artist_type "2"^^xs:short.
?artist rel:collaboratesWith ?any1 .
}
}
ORDER BY ?label
有道理,而且看起来可读性强("retrieve all mo:MusicArtist
items minus those that are collaborations with individual members listed")。
我没有立即找到解决方案。我首先想到将三个单独的案例放在一起 UNION
:
SELECT *
WHERE
{
?artist a mo:MusicArtist.
?artist rdfs:label ?label.
# Single artists
{
?artist vocab:artist_type "1"^^xs:short.
}
UNION
# Groups for which there is no defined collaboration with single persons
{
?artist vocab:artist_type "2"^^xs:short.
FILTER NOT EXISTS
{
?artist rel:collaboratesWith ?any1
}
}
UNION
# Some artists don't have this attribute
{
FILTER NOT EXISTS
{
?artist vocab:artist_type ?any2
}
}
}
ORDER BY ?label
我发现第三个 UNION
语句,即应该添加 mo:MusicArtist
项但没有 vocab:artist_type
的语句,没有用。也就是说,他们没有找到 "René Marie".
等项目
虽然我对 MINUS
找到的最短解决方案感到满意,但我不明白为什么旧的解决方案不起作用。很明显,我遗漏了一些 FILTER NOT EXISTS
可能对其他情况有用的要点。
欢迎任何帮助。
当我 运行 以下查询时,我得到的结果听起来像您正在寻找的结果:
select distinct ?label where {
?artist a mo:MusicArtist ;
rdfs:label ?label .
#-- artists with type 1
{
?artist vocab:artist_type "1"^^xs:short
}
#-- artists with no type
union {
filter not exists {
?artist vocab:artist_type ?type
}
}
#-- artists with type 2 that have no
#-- collaborators
union {
?artist vocab:artist_type "2"^^xs:short
filter not exists {
?artist rel:collaboratesWith ?another
}
}
}
------------------------------------
| label |
====================================
| "René Marie" |
| "Pat Metheny & Anna Maria Jopek" |
| "Edvard Grieg" |
------------------------------------
不过,我不知道我是否看到这与您的有什么本质上的不同。不过,我确实认为您可以稍微清理一下这个查询。您可以使用 optional 和 values 来指定类型是可选的,但如果存在则必须是 1 或 2。然后您可以添加一个过滤器要求值为2时,没有合作者
select ?label where {
#-- get an artist and their label
?artist a mo:MusicArtist ;
rdfs:label ?label .
#-- and optionally their type, if it is
#-- "1"^^xs:short or "2"^^xs:short
optional {
values ?type { "1"^^xs:short "2"^^xs:short }
?artist vocab:artist_type ?type
}
#-- if ?type is "2"^^xs:short, then ?artist
#-- must not collaborate with anyone.
filter ( !sameTerm(?type,"2"^^xs:short)
|| not exists { ?artist rel:collaboratesWith ?anyone })
}
------------------------------------
| label |
====================================
| "René Marie" |
| "Pat Metheny & Anna Maria Jopek" |
| "Edvard Grieg" |
------------------------------------
几年前我学习了一些语义技术,包括RDF和SPARQL,然后有一段时间没有机会使用它们。现在我开始了一个使用 OpenRDF 2.8.0 作为语义存储的新项目,我正在恢复我的知识,尽管我有一些遗忘的东西需要恢复。
特别是,在过去的几天里,我在正确理解 SPARQL 中的 FILTER NOT EXIST 结构方面遇到了一些麻烦。
问题:我有一个从 DbTune.org(音乐本体)导入的语义存储。 mo:MusicArtist
,作为 mo:Track
的 foaf:maker
,可以出现在四种情况下(我只列出相关陈述):
<http://dbtune.org/musicbrainz/resource/artist/013c8e5b-d72a-4cd3-8dee-6c64d6125823> a mo:MusicArtist ;
vocab:artist_type "1"^^xs:short ;
rdfs:label "Edvard Grieg" .
<http://dbtune.org/musicbrainz/resource/artist/032df978-9130-490e-8857-0c9ef231fae8> a mo:MusicArtist ;
vocab:artist_type "2"^^xs:short ;
rel:collaboratesWith <http://dbtune.org/musicbrainz/resource/artist/3db5dfb1-1b91-4038-8268-ae04d15b6a3e> , <http://dbtune.org/musicbrainz/resource/artist/d78afc01-f918-440c-89fc-9d546a3ba4ac> ;
rdfs:label "Doris Day & Howard Keel".
<http://dbtune.org/musicbrainz/resource/artist/1645f335-2367-427d-8e2d-ad206946a8eb> a mo:MusicArtist ;
vocab:artist_type "2"^^xs:short ;
rdfs:label "Pat Metheny & Anna Maria Jopek".
<http://dbtune.org/musicbrainz/resource/artist/12822d4f-4607-4f1d-ab16-d6bacc27cafe> a mo:MusicArtist ;
rdfs:label "René Marie".
据我了解,vocab:artist_type
对于单个艺术家(示例 #1)是 1
,对于合作组(示例 #2 和 #3)是 2
。在这种情况下,可能有几个 rel:collaboratesWith
语句指向组或协作的单个成员的描述(示例 #2)。在某些情况下,缺少 vocab:artist_type
语句(示例 #4)。
现在我想尽可能将所有艺术家提取为单个实体。我的意思是,我不想检索示例 #2,因为我将分别获得 "Doris Day" 和 "Howard Keel"。我必须检索示例 #3 "Pat Metheny & Anna Maria Jopek",因为我无能为力。当然我也想检索"René Marie".
我已经用这个 SPARQL 以令人满意的方式解决了这个问题:
SELECT *
WHERE
{
?artist a mo:MusicArtist.
?artist rdfs:label ?label.
MINUS
{
?artist vocab:artist_type "2"^^xs:short.
?artist rel:collaboratesWith ?any1 .
}
}
ORDER BY ?label
有道理,而且看起来可读性强("retrieve all mo:MusicArtist
items minus those that are collaborations with individual members listed")。
我没有立即找到解决方案。我首先想到将三个单独的案例放在一起 UNION
:
SELECT *
WHERE
{
?artist a mo:MusicArtist.
?artist rdfs:label ?label.
# Single artists
{
?artist vocab:artist_type "1"^^xs:short.
}
UNION
# Groups for which there is no defined collaboration with single persons
{
?artist vocab:artist_type "2"^^xs:short.
FILTER NOT EXISTS
{
?artist rel:collaboratesWith ?any1
}
}
UNION
# Some artists don't have this attribute
{
FILTER NOT EXISTS
{
?artist vocab:artist_type ?any2
}
}
}
ORDER BY ?label
我发现第三个 UNION
语句,即应该添加 mo:MusicArtist
项但没有 vocab:artist_type
的语句,没有用。也就是说,他们没有找到 "René Marie".
虽然我对 MINUS
找到的最短解决方案感到满意,但我不明白为什么旧的解决方案不起作用。很明显,我遗漏了一些 FILTER NOT EXISTS
可能对其他情况有用的要点。
欢迎任何帮助。
当我 运行 以下查询时,我得到的结果听起来像您正在寻找的结果:
select distinct ?label where {
?artist a mo:MusicArtist ;
rdfs:label ?label .
#-- artists with type 1
{
?artist vocab:artist_type "1"^^xs:short
}
#-- artists with no type
union {
filter not exists {
?artist vocab:artist_type ?type
}
}
#-- artists with type 2 that have no
#-- collaborators
union {
?artist vocab:artist_type "2"^^xs:short
filter not exists {
?artist rel:collaboratesWith ?another
}
}
}
------------------------------------
| label |
====================================
| "René Marie" |
| "Pat Metheny & Anna Maria Jopek" |
| "Edvard Grieg" |
------------------------------------
不过,我不知道我是否看到这与您的有什么本质上的不同。不过,我确实认为您可以稍微清理一下这个查询。您可以使用 optional 和 values 来指定类型是可选的,但如果存在则必须是 1 或 2。然后您可以添加一个过滤器要求值为2时,没有合作者
select ?label where {
#-- get an artist and their label
?artist a mo:MusicArtist ;
rdfs:label ?label .
#-- and optionally their type, if it is
#-- "1"^^xs:short or "2"^^xs:short
optional {
values ?type { "1"^^xs:short "2"^^xs:short }
?artist vocab:artist_type ?type
}
#-- if ?type is "2"^^xs:short, then ?artist
#-- must not collaborate with anyone.
filter ( !sameTerm(?type,"2"^^xs:short)
|| not exists { ?artist rel:collaboratesWith ?anyone })
}
------------------------------------
| label |
====================================
| "René Marie" |
| "Pat Metheny & Anna Maria Jopek" |
| "Edvard Grieg" |
------------------------------------