可以使这个 SPARQL 搜索查询更有效率吗?

Can this SPARQL search query be made more efficient?

我有一个在 SPARQL 中进行的复合 'search' 查询

(1) 搜索属于特定 rdf:type:

的唯一主题 URI

示例:

SELECT ?s FROM NAMED <http://www.example.org/graph1> FROM NAMED <http://www.example.org/graph2>
{
   GRAPH ?g
   {
      ?s <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.example.org/widget>.
   }
} OFFSET 10000 LIMIT 100

这个查询非常简单,只是 returns 所有 'widget' 类型的主题。

(2) 对于满足主题URI的返回页面,搜索所有引用这些主题URI(即引用实体)的主题URI,指定指示引用的引用谓词URI。

假设之前的查询 (1) 返回了 2 个主题 URI http://www.example.org/widget100 and http://www.example.org/widget101 and the referencing predicate I wanted to query for was http://www.example.org/widget:

示例:

SELECT ?s FROM NAMED <http://www.example.org/graph1> FROM NAMED <http://www.example.org/graph2>
WHERE {
   UNION
   {
      ?s <http://www.example.org/widget> <http://www.example.org/widget100>
   }
   UNION
   {
      ?s <http://www.example.org/widget> <http://www.example.org/widget101>
   }
}

如果上一页返回 100 个主题 URI,则此处每个主题将有 100 个 'UNION' 语句。

此查询有效 - 它选择给定类型的主题 URI,以及 returns 使用给定引用谓词引用那些主题的附加主题 URI。

问题实际上是,当我的查询图中有 100,000 个三元组时,即使在内存图上的快速机器上,此查询通常也需要 1 分钟以上的时间来执行。对于这种相当典型的搜索场景,这对于用户来说太慢了。

根据分析,这两个查询大约占用查询时间的 50%。

我有足够的 SPARQL 经验来构建上面这样的查询,但我当然不是专家。我想知道是否可以提高效率。例如,是否可以将其组合成一个查询,至少可以将查询时间减少 50% 以上?我在潜在的许多主题中使用 UNION 是否可以用更有效的方法替换?

谢谢

SPARQL 专家

UPDATE:我已设法将查询减少为以下形式的单个查询:

SELECT  *
  FROM NAMED <http://www.example.org/widgets>
  FROM NAMED <http://www.example.org/widgetstats>
  FROM NAMED <http://www.example.org/widgetmetadata>
  FROM NAMED <http://www.example.org/widgetfactory>
  WHERE
    {   { SELECT  ?s ?p ?o
          WHERE
            { GRAPH ?g
                { ?s  ?p  ?o }
              { SELECT  ?s
                WHERE
                  { GRAPH ?i
                      { ?s  a  <http://www.example.org/widget> }
                  }
                OFFSET  0
                LIMIT   100
              }
            }
        }
      UNION
        { SELECT  ?s ?p ?o
          WHERE
            { GRAPH ?g
                { ?s  ?p  ?o }
              { SELECT DISTINCT  ?s
                WHERE
                  { GRAPH ?h
                      { OPTIONAL
                          { ?s  <http://www.example.org/widgetstats/widget>  ?x }
                        OPTIONAL
                          { ?s  <http://www.example.org/widgetmetadata/widget>  ?x }
                        OPTIONAL
                          { ?s  <http://www.example.org/widgetfactory/widget>  ?x }
                      }
                    { SELECT  ?x
                      WHERE
                        { GRAPH ?i
                            { ?x  a  <http://www.example.org/widget> }
                        }
                      OFFSET  0
                      LIMIT   100
                    }
                  }
              }
            }
        }
    }

这将查询速度提高了大约50%。不过,我认为查询可以变得更快。这种形式的查询 - 首先获取与给定类型的主要实体关联的所有三元组,然后是与引用实体关联的所有三元组 - 需要两个相同的最内层子查询,获取给定类型的唯一主题。

是否有任何方法可以减少此查询 - 也许使用单个查询而不是两个子查询的 UNION 来执行?我假设这可能会进一步提高性能。

更新 2:我无法改进上面的查询(第一次更新),所以我暂时将其作为答案。

如果您仍然想要第一个查询的分页,那么最好的方法可能是使用 SPARQL subquery.

组合查询

请注意,对于子查询,您是从内向外工作的,因此子查询会选择小部件,而外部查询会展开以查找引用。如果您使用的是 FROM NAMED,那么您需要在图表上进行匹配(假设您的结果在命名图表中并且您没有使用联合默认图表)。内部查询中的 OFFSET 和 LIMIT 意味着下面的示例 returns 引用了第三个小部件(引擎应用的任何默认排序顺序)。

我不确定这是否会加快整体查询时间,但值得尝试并为您节省大量字符串连接!

PREFIX ex: <http://www.example.org/>
SELECT ?s FROM NAMED ex:g1 FROM NAMED ex:g2 WHERE {
  GRAPH ?h {
    ?s ex:widget ?x
  }
  {
    SELECT ?x WHERE {
      GRAPH ?g {
        ?x a ex:widget
      } 
    } OFFSET 2 LIMIT 1
  }
}