为什么这个 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 还提供了添加关于理想操作顺序的提示的功能,这在这里可能很有用。