UNION 中的 SPARQL BIND 太慢

SPARQL BIND inside UNION is too slow

给定一个 IMDb ID,我想从维基数据中获取该电影的导演和演员列表。

问题是,我想将导演和演员查询联合到一个列中,同时还提供一个包含导演或演员角色的新列。

整体查询非常简单:首先我从 IMDb ID 获取电影实体,然后我获取该电影的所有导演,然后获取该电影的所有演员并在填充新列时将他们联合在一起(?role) 与角色。

这是我的:

PREFIX p: <http://www.wikidata.org/prop/>
PREFIX ps: <http://www.wikidata.org/prop/statement/>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
SELECT ?person ?personLabel ?role ?imdb WHERE
{
  ?movie wdt:P345 "tt0110912" .
  { ?movie p:P57 ?cast .
    ?cast ps:P57 ?person .
    BIND("director" as ?role) .
  } UNION {
    ?movie p:P161 ?cast .
    ?cast ps:P161 ?person .
    BIND("actor" as ?role) . }
  
  ?person wdt:P345 ?imdb .
  OPTIONAL { ?cast prov:wasDerivedFrom ?ref . }
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
GROUP BY ?person ?personLabel ?role ?imdb
ORDER BY DESC(?role)
LIMIT 100

这有效并给出了我想要的结果,问题是它需要大约 10 秒。如果我删除 BIND 的即时速度,但我没有得到包含角色的列。

我猜想 BIND 会导致查询优化器出现一些问题。您可以尝试将角色绑定到 UNION 子句之外,即

PREFIX p: <http://www.wikidata.org/prop/>
PREFIX ps: <http://www.wikidata.org/prop/statement/>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
SELECT ?person ?personLabel ?role ?imdb WHERE
{
  ?movie wdt:P345 "tt0110912" .
  ?person wdt:P345 ?imdb .
  { 
     ?movie p:P57 ?c1 . ?c1 ps:P57 ?person .
     ?movie p:P57 ?cast .
  } UNION {
     ?movie p:P161 ?c2 . ?c2 ps:P161 ?person .
     ?movie p:P161 ?cast . 
  }
  BIND(IF(bound(?c1), "director", "actor") as ?role)

  OPTIONAL { ?cast prov:wasDerivedFrom ?ref . }
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
GROUP BY ?person ?personLabel ?role ?imdb
ORDER BY DESC(?role)
LIMIT 100

(如果没有 ?ref 变量,可以省略三元组模式以检索 UNION 子句中的 ?cast。)

我会使用 values 而不是 bindunion 来编写此代码。这个想法是,当属性是一回事时,?role 是一回事,而当属性是另一回事时,?role 又是另一回事。使用 values 的简单方法如下:

select ?owner ?pet ?petType {
  values (?hasPet ?petType) { 
    (:hasCat "cat")
    (:hasDog "dog")
  }
  ?owner ?hasPet ?pet
}

在你的情况下,这将是:

PREFIX p: <http://www.wikidata.org/prop/>
PREFIX ps: <http://www.wikidata.org/prop/statement/>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
SELECT ?person ?personLabel ?role ?imdb WHERE
{
  ?movie wdt:P345 "tt0110912" .

  values (?p ?ps ?role) {
    (p:P161 ps:P161 "actor")
    (p:P57 ps:P57 "director")
  }
  ?movie ?p ?cast .
  ?cast ?ps ?person .

  ?person wdt:P345 ?imdb .
  OPTIONAL { ?cast prov:wasDerivedFrom ?ref . }
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
GROUP BY ?person ?personLabel ?role ?imdb
ORDER BY DESC(?role)
LIMIT 100

当我在 query.wikidata.org 运行 时,它几乎立即产生 35 results