About UNION and FILTER NOT EXISTS in SPARQL (OpenRDF 2.8.0)


几年前

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

特别是,在过去的几天里,我在正确取消SPARQL中的过滤器不存在结构时遇到了一些麻烦。

问题:我有一个从 DbTune.org(音乐本体(导入的语义存储。一个mo:MusicArtist,旨在作为mo:Trackfoaf: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",因为我不能做任何其他事情。当然,我也想找回"勒内玛丽"。

我已经用这个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

这是有道理的,看起来是可读的("检索所有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项目而没有vocab:artist_type的语句,不起作用。也就是说,他们没有找到"勒内玛丽"之类的物品。

虽然我对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"                   |
------------------------------------

不过,我不知道我是否看到这与您的本质不同。 我确实认为您可以稍微清理一下此查询。可以使用 Optionalvalues 来指定类型是可选的,但如果存在,则必须为 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"                   |
------------------------------------

最新更新