昂贵的SPARQL操作,比较指南

时间:2014-08-06 13:43:40

标签: sparql

在运行SPARQL查询和您编写的代码之间需要权衡清理结果 复杂查询: Pros获取干净/高效的结果,减少清理代码 Cons: 超时错误,处理时间长
 我知道有人不能概括它,但想比较梳理子查询(UNION,...),过滤器和聚合,看看在超时的情况下哪一个是更昂贵的操作。
 例如,我从日语SPARQL端点运行此查询(我删除了它的一部分)。

SELECT ?film ?dblink ?filmType (group_concat(?actors ; separator = "|") AS ?actorset) (group_concat(?country ; separator = "|") AS ?countryset) (group_concat(?releaseDate ; separator = "|") AS ?releasedateset) (group_concat(?language ; separator = "|") AS ?languageset) (group_concat(?genre ; separator = "|") AS ?genreset) ?numberOfEpisodes  ?numberOfSeasons
WHERE {
     {?film a dbpedia-owl:Film } UNION {?film a dbpedia-owl:TelevisionShow } UNION {?film a dbpedia-owl:Cartoon } UNION {?film a dbpedia-owl:TelevisionSeason } .
     {?film a ?filmType  } .Filter(regex(?filmType,"(?:TelevisionSeason|Cartoon|Film|TelevisionShow)")) .
     OPTIONAL { {?film dbpedia-owl:starring ?actors} UNION {?film dbpprop:starring ?actors}  }. OPTIONAL { ?film dbpedia-owl:country ?country  }.  OPTIONAL { {?film dbpprop:genre ?genre} UNION  { ?film dbpedia-owl:genre ?genre  } }. OPTIONAL { {?film dbpprop:language ?language} UNION {?film dbpedia-owl:language ?language}  }. OPTIONAL { ?film dbpedia-owl:wikiPageID ?wikiPageID   } .
     OPTIONAL {?film owl:sameAs ?dblink . Filter (strstarts( str(?dblink), 'http://dbpedia.org/resource/'))}
 } LIMIT 5

它超时了。什么更有效(以避免超时)在我的代码中删除和处理结果?
1-聚合(group_concat)
2-过滤器:在我的代码中对其进行后期处理 3-子查询:删除一些子查询(Optional vs Union)并在另一个查询中执行它们

1 个答案:

答案 0 :(得分:5)

优化问题很难,特别是当端点可以施加不同的限制时。也就是说,至少有一些东西可以简化这个查询。

寻找某些类别的人

{?film a dbpedia-owl:Film } UNION {?film a dbpedia-owl:TelevisionShow } UNION {?film a dbpedia-owl:Cartoon } UNION {?film a dbpedia-owl:TelevisionSeason } .

应该是:

values ?filmType { dbpedia-owl:Film
                   dbpedia-owl:Television
                   dbpedia-owl:Cartoon
                   dbpedia-owl:TelevisionSeason }
?film a ?filmType

这将处理所有固定类型。下一部分

filter(regex(?filmType,"(?:TelevisionSeason|Cartoon|Film|TelevisionShow)"))

似乎旨在查找具有包含其中一个字符串的类型的任何内容。这可能会遍历所有个体及其所有类型,然后在所有类型上运行正则表达式。啊。更好的方法是找到名称与该东西匹配的本体类,然后检索这些类的个体。

(请注意,除此之外,卡通可能会提到非电影事物;例如报纸上的政治漫画。)

也就是说,一个更好的解决方案可能是稍微浏览一下类层次结构,看看是否有一些你感兴趣的东西的常见超类。如果某个东西是子类的成员,那么它也是超类的成员,所以你可以通过这种方式保存一些查询。

查找可选属性

OPTIONAL { {?film dbpedia-owl:starring ?actors} UNION
           {?film dbpprop:starring ?actors}           } .
OPTIONAL { ?film dbpedia-owl:country ?country  } . 
OPTIONAL { {?film dbpprop:genre ?genre } UNION
           {?film dbpedia-owl:genre ?genre  } }.
OPTIONAL { {?film dbpprop:language ?language} UNION
           {?film dbpedia-owl:language ?language}  }.
OPTIONAL { ?film dbpedia-owl:wikiPageID ?wikiPageID   } .

除了:

之外,你可以做些什么来清理它们
  1. dbpedia-owl:属性比dbpprop:properties具有更清晰的数据,因此如果您跳过dbpprop:properties,您将获得更好的结果。
  2. 也就是说,如果你想要获得超过属性的值,只需在属性路径中使用交替构造即可。例如,第一个可选块变为:

    OPTIONAL { {?film dbpedia-owl:starring|dbpprop:starring ?actors }
    

    摆脱了联盟,使你的查询更简单。

  3. 匹配资源以给定的命名空间开头

    OPTIONAL { ?film owl:sameAs ?dblink .
               Filter (strstarts( str(?dblink), 'http://dbpedia.org/resource/'))}
    

    这并不坏,虽然owl:sameAs是传递性和反身性的,所以你应该让链接朝着两个方向前进。此外(这并不重要),您可以使用str获取前缀,使您的查询更易于维护。因此:

    prefix dbpedia: <http://dbpedia.org/resource/>
    
    optional { ?film (owl:sameAs|^owl:sameAs)* ?dblink .
               filter (strstarts( str(?dblink), str(:dbpedia) ) }
    

    聚合函数

    SELECT
      ?film ?dblink ?filmType
      (group_concat(?actors ; separator = "|") AS ?actorset)
      (group_concat(?country ; separator = "|") AS ?countryset)
      (group_concat(?releaseDate ; separator = "|") AS ?releasedateset)
      (group_concat(?language ; separator = "|") AS ?languageset)
      (group_concat(?genre ; separator = "|") AS ?genreset)
      ?numberOfEpisodes ?numberOfSeasons
    WHERE { … }
    LIMIT 5
    

    您正在使用多个group_concat聚合。这可能本身并不是一个问题,因为它只是遍历每个组并构建一个字符串。这与您拥有的结果数量(在群组之前)呈线性关系,所以它不应该太昂贵。但是,选择组和非分组变量时,是合法的。如果您要在没有聚合的情况下选择五个变量,则需要通过以下方式明确使用组:

    SELECT
      ?film ?dblink ?filmType
      (group_concat(?actors ; separator = "|") AS ?actorset)
      (group_concat(?country ; separator = "|") AS ?countryset)
      (group_concat(?releaseDate ; separator = "|") AS ?releasedateset)
      (group_concat(?language ; separator = "|") AS ?languageset)
      (group_concat(?genre ; separator = "|") AS ?genreset)
      ?numberOfEpisodes ?numberOfSeasons
    WHERE {  }
    GROUP BY ?film ?dblink ?filmType ?numberOfEpisodes ?numberOfSeasons
    LIMIT 5
    

    我知道Virtuoso可以在没有显式组的情况下接受查询,但在SPARQL中。事实上,我回答了最近的答案.semanticweb.com问题,Variable used when already in-scope error触及了这一点。在sparql.org's validator中查看您的查询是个不错的主意。