在 SPARQL 查询中按 birthYear 和 deathYear 标准过滤人员更具性能

Make filtering people by birthYear and deathYear criteria more performative in SPARQL query

我想找到在质数年出生和去世的科学家的实例。基于先前在 this URL 上的讨论,我设计了以下查询,该查询很笨拙且会超时:

SELECT ?birthYear ?deathYear ?scientist ?scientistLabel 
WHERE 
{ 
 {
  select ?value1
    { 
      ?number wdt:P31 wd:Q49008. 
      ?number wdt:P1181 ?value1 
      filter(?value1 < year(now())) 
    }
  }
  {
  select ?value2
    { 
      ?number wdt:P31 wd:Q49008. 
      ?number wdt:P1181 ?value2 
      filter(?value2 < ?value1)
    }
  }
  ?scientist wdt:P106 wd:Q901. 
  ?scientist wdt:P570 ?deathDate.
  ?scientist wdt:P569 ?birthDate
  BIND(year(?deathDate) as ?deathYear) 
  BIND(year(?birthDate) as ?birthYear)
  filter(?deathYear = ?value1)
  filter(?birthYear = ?value2)
  SERVICE wikibase:label { bd:serviceParam wikibase:language " [AUTO_LANGUAGE],en". } 
} 
order by asc(?deathYear) asc(?scientistLabel) 
limit 100

我是 SPARQL 新手,但据我所知,这将取一对质数,然后查看职业为 'scientist' 的人是否在与第一个对应的年份死亡,那么如果那个人出生在对应于2号的那一年。 有没有办法提高这个查询的性能?

您的查询有 2 个问题:

  1. 不能以这种方式将值传递到子查询(参见 Bottom Up Semantics)。
  2. wdt:P1181 的值为 xsd:decimal,而 year() returns xsd:integer。一个人被迫使用 FILTER(?birthYear = ?value) ,它的性能和可优化性都比简单的连接差。看来 Blazegraph 必须过早地具体化解决方案。

因此,您的查询应该是:

SELECT DISTINCT ?scientist ?scientistLabel ?birthYear ?deathYear {
  {
    SELECT (xsd:integer(?value1) as ?birthYear) { 
      ?number wdt:P31 wd:Q49008. 
      ?number wdt:P1181 ?value1 
      FILTER(?value1 < year(now())) 
    }
  }
  {
    SELECT (xsd:integer(?value2) AS ?deathYear) { 
      ?number wdt:P31 wd:Q49008. 
      ?number wdt:P1181 ?value2 
      FILTER(?value2 < year(now()))
    }
  }
  ?scientist wdt:P106 wd:Q901.
  ?scientist wdt:P570 ?deathDate.
  ?scientist wdt:P569 ?birthDate.
  FILTER(isLiteral(?birthDate) && isLiteral(?deathDate))
  BIND(year(?deathDate) AS ?deathYear) 
  BIND(year(?birthDate) AS ?birthYear)
  SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". } 
} ORDER BY ASC(?birthDate) ASC(?deathDate)

Try it

我还添加了 FILTER(isLiteral(?birthDate)),因为 wdt:P1181 的值可能是 unknown values(即 RDF 空白节点),在这种情况下 BIND (year(?birthDate) AS ?birthYear) 投影变量始终未绑定并匹配连接中的所有内容。


您可以使用 Blazegraph 特定技巧进一步加快查询速度:

SELECT DISTINCT ?scientist ?scientistLabel ?birthYear ?deathYear
   WITH {
    SELECT (xsd:integer(?value) AS ?year) {
      [] wdt:P31 wd:Q49008 ; wdt:P1181 ?value. 
      hint:Prior hint:rangeSafe true.
      FILTER(?value  <= year(now()))
    }
  } AS %primes {
    # hint:Query hint:maxParallel 50 . 
    # hint:Query hint:chunkSize 250 . 
  { SELECT (?year AS ?birthYear)  { include %primes } }
  { SELECT (?year AS ?deathYear)  { include %primes } } 
  ?scientist wdt:P106 wd:Q901.
  ?scientist wdt:P570 ?deathDate.
  ?scientist wdt:P569 ?birthDate.
  FILTER (isLiteral(?deathDate) && isLiteral(?birthDate))
  BIND (year(?birthDate) AS ?birthYear)
  BIND (year(?deathDate) AS ?deathYear)
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en" }
} ORDER BY ASC(?birthYear) ASC (?deathYear)

Try it