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 而不是 bind 和 union 来编写此代码。这个想法是,当属性是一回事时,?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。
给定一个 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 而不是 bind 和 union 来编写此代码。这个想法是,当属性是一回事时,?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。