为什么这个 SPARQL 查询超时,如何优化这个查询?
Why this SPARQL query times out and how to optimize this query?
我有这个 SPARQL 查询,我 运行 通过 Wikidata 的端点
SELECT ?bLabel ?b ?hLabel ?a ?cLabel
WHERE
{
wd:Q11462 ?a ?b.
wd:Q11095 ?a ?b.
?c ?a ?b.
?h wikibase:directClaim ?a .
SERVICE wikibase:label { bd:serviceParam wikibase:language "en" }
}
本质上,我正在寻找 wd:Q11462 和 wd:Q11095 共享的关系,看看还有什么共享这种关系。它达到了 60 秒的时间限制。
但是,如果我 运行 分两部分进行多次查询:
首先,获取共享关系
SELECT ?bLabel ?b ?hLabel ?a
WHERE
{
wd:Q11462 ?a ?b.
wd:Q11095 ?a ?b.
?h wikibase:directClaim ?a .
SERVICE wikibase:label { bd:serviceParam wikibase:language "en" }
}
然后,对于每个获得的关系,运行 一个查询,查找其他与他们共享的内容。
"""
SELECT ?cLabel
WHERE
{
?c wdt:P131 wd:Q3586.
SERVICE wikibase:label { bd:serviceParam wikibase:language "en" }
}
"""
整个查询 运行 只用了 2.5 秒。
由于限制,我希望只用一次查询就能达到同样的速度。我该怎么办?
这是一种使用子查询的方法。需要六秒:
SELECT ?cLabel
WITH {
SELECT ?bLabel ?b ?hLabel ?a
WHERE {
wd:Q11462 ?a ?b.
wd:Q11095 ?a ?b.
?h wikibase:directClaim ?a .
}
} as %results
WHERE {
INCLUDE %results.
?c wdt:P131 wd:Q3586.
SERVICE wikibase:label { bd:serviceParam wikibase:language "en" }
}
鉴于您观察到的明显差异以及它们在概念上与您连续 运行 多个查询的方法有多接近,子查询是自然扩展。一个通常有用的更通用的技巧是用手动查询标签替换标签服务。
在切换到一些(常见)语句较少的项目后,我说服了查询服务 explain itself。我不能完全理解该输出,但据我所知,标签服务将其丢弃(底部 table 中的第 5 行):
9 com.bigdata.bop.BOp.bopId
CONTROLLER com.bigdata.bop.BOp.evaluationContext
false com.bigdata.bop.PipelineOp.pipelined
true com.bigdata.bop.PipelineOp.sharedState
ServiceNode com.bigdata.bop.controller.ServiceCallJoin.serviceNode
wdq com.bigdata.bop.controller.ServiceCallJoin.namespace
1596209250127 com.bigdata.bop.controller.ServiceCallJoin.timestamp
[b, h, c] com.bigdata.bop.join.HashJoinAnnotations.joinVars
null com.bigdata.bop.join.JoinAnnotations.constraints
似乎它当时试图为 20000 多个项目填充标签。除了将其排除在第一个查询之外,SPARQL 还提供了添加关于理想操作顺序的提示的功能,这在这里可能很有用。
我有这个 SPARQL 查询,我 运行 通过 Wikidata 的端点
SELECT ?bLabel ?b ?hLabel ?a ?cLabel
WHERE
{
wd:Q11462 ?a ?b.
wd:Q11095 ?a ?b.
?c ?a ?b.
?h wikibase:directClaim ?a .
SERVICE wikibase:label { bd:serviceParam wikibase:language "en" }
}
本质上,我正在寻找 wd:Q11462 和 wd:Q11095 共享的关系,看看还有什么共享这种关系。它达到了 60 秒的时间限制。
但是,如果我 运行 分两部分进行多次查询:
首先,获取共享关系
SELECT ?bLabel ?b ?hLabel ?a
WHERE
{
wd:Q11462 ?a ?b.
wd:Q11095 ?a ?b.
?h wikibase:directClaim ?a .
SERVICE wikibase:label { bd:serviceParam wikibase:language "en" }
}
然后,对于每个获得的关系,运行 一个查询,查找其他与他们共享的内容。
"""
SELECT ?cLabel
WHERE
{
?c wdt:P131 wd:Q3586.
SERVICE wikibase:label { bd:serviceParam wikibase:language "en" }
}
"""
整个查询 运行 只用了 2.5 秒。
由于限制,我希望只用一次查询就能达到同样的速度。我该怎么办?
这是一种使用子查询的方法。需要六秒:
SELECT ?cLabel
WITH {
SELECT ?bLabel ?b ?hLabel ?a
WHERE {
wd:Q11462 ?a ?b.
wd:Q11095 ?a ?b.
?h wikibase:directClaim ?a .
}
} as %results
WHERE {
INCLUDE %results.
?c wdt:P131 wd:Q3586.
SERVICE wikibase:label { bd:serviceParam wikibase:language "en" }
}
鉴于您观察到的明显差异以及它们在概念上与您连续 运行 多个查询的方法有多接近,子查询是自然扩展。一个通常有用的更通用的技巧是用手动查询标签替换标签服务。
在切换到一些(常见)语句较少的项目后,我说服了查询服务 explain itself。我不能完全理解该输出,但据我所知,标签服务将其丢弃(底部 table 中的第 5 行):
9 com.bigdata.bop.BOp.bopId
CONTROLLER com.bigdata.bop.BOp.evaluationContext
false com.bigdata.bop.PipelineOp.pipelined
true com.bigdata.bop.PipelineOp.sharedState
ServiceNode com.bigdata.bop.controller.ServiceCallJoin.serviceNode
wdq com.bigdata.bop.controller.ServiceCallJoin.namespace
1596209250127 com.bigdata.bop.controller.ServiceCallJoin.timestamp
[b, h, c] com.bigdata.bop.join.HashJoinAnnotations.joinVars
null com.bigdata.bop.join.JoinAnnotations.constraints
似乎它当时试图为 20000 多个项目填充标签。除了将其排除在第一个查询之外,SPARQL 还提供了添加关于理想操作顺序的提示的功能,这在这里可能很有用。