关于SPARQL中的UNION和FILTER NOT EXISTS(OpenRDF 2.8.0)

时间:2015-04-09 10:34:05

标签: sparql sesame

几年前,我学会了一些语义技术,包括RDF和SPARQL,然后我有一段时间没有机会与它们合作。现在我已经开始了一个新项目,它使用OpenRDF 2.8.0作为语义存储,我正在恢复我的知识,即使我有一些被遗忘的东西需要恢复。

特别是,在过去的几天里,我在SPARQL中正确地使用FILTER NOT EXIST构造时遇到了一些麻烦。

问题:我有一个从DbTune.org(音乐本体)导入的语义存储。预计为mo:MusicArtist foaf:maker的{​​{1}}可以出现在四种情况中(我只列出相关陈述):

mo:Track

根据我的理解, <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". 对于单个艺术家(示例#1)是vocab:artist_type,对于协作组(示例#2和#3)是1。在这种情况下,可能会有一些2语句指向组或协作的单个成员的描述(示例#2)。在某些情况下,缺少rel:collaboratesWith语句(例如#4)。

现在我想将所有艺术家作为单一实体提取出来。我的意思是,我不想找回第2个例子,因为我会分别得到“Doris Day”和“Howard Keel”。我必须找回示例#3“Pat Metheny&amp; Anna Maria Jopek”,因为我不能做任何其他事情。当然,我也想要找回“RenéMarie”。

我用这个SPARQL以令人满意的方式解决了这个问题:

vocab:artist_type

这是有道理的,看起来它是可读的(“检索所有 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 项目减去那些与列出的个别成员合作的项目”)。

我没有立即找到解决方案。我首先想到用mo:MusicArtist

组合三个独立的案例
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的语句,却没有用。也就是说,他们没有找到像“RenéMarie”这样的物品。

虽然我对vocab:artist_type找到的最短解决方案感到满意,但我不明白我不明白为什么旧解决方案无效。显然,我对MINUS遗漏了一些可能对其他案例有用的观点。

欢迎任何帮助。

1 个答案:

答案 0 :(得分:3)

当我运行以下查询时,我得到的结果听起来像是你正在寻找:

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"                   |
------------------------------------

不过,我不知道这与你的不同之处。我认为你可以稍微清理一下这个查询。您可以使用可选指定该类型是可选的,但如果存在必须为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"                   |
------------------------------------