SPARQL 可选查询

13

我有以下turtle格式的RDF

    @prefix ab: <http://learningsparql.com/ns/addressbook#> .
    @prefix d: <http://learningsparql.com/ns/data#> .
    d:i0432 ab:firstName "Richard" .
    d:i0432 ab:lastName "Mutt" .
    d:i0432 ab:homeTel "(229) 276-5135" .
    d:i0432 ab:nick "Dick" .
    d:i0432 ab:email "richard49@hotmail.com" .
    d:i9771 ab:firstName "Cindy" .
    d:i9771 ab:lastName "Marshall" .
    d:i9771 ab:homeTel "(245) 646-5488" .
    d:i9771 ab:email "cindym@gmail.com" .
    d:i8301 ab:firstName "Craig" .
    d:i8301 ab:lastName "Ellis" .
    d:i8301 ab:workTel "(245) 315-5486" .
    d:i8301 ab:email "craigellis@yahoo.com" .
    d:i8301 ab:email "c.ellis@usairwaysgroup.com" .

查询条件是:

    PREFIX ab: <http://learningsparql.com/ns/addressbook#>
    SELECT ?first ?last
    WHERE
    {
        ?s ab:lastName ?last .
        OPTIONAL {?s ab:nick ?first. }.
        OPTIONAL {?s ab:firstName ?first .}.
    }

结果是

    ------------------------
    | first   | last       |
    ========================
    | "Craig" | "Ellis"    |
    | "Cindy" | "Marshall" |
    | "Dick"  | "Mutt"     |
    ------------------------

但是如果我将查询更改为

    PREFIX ab: <http://learningsparql.com/ns/addressbook#>
    SELECT ?first ?last
    WHERE
    {
        OPTIONAL {?s ab:nick ?first. }.
        OPTIONAL {?s ab:firstName ?first .}.
        ?s ab:lastName ?last .
    }

结果为

    -------------------
    | first  | last   |
    ===================
    | "Dick" | "Mutt" |
    -------------------

有人能解释一下是什么原因造成了这种差异吗?我以为SPARQL查询中的句点和“and”操作符是一样的。

2个回答

20

这里的顺序很重要。

SPARQL查询的语义是通过SPARQL代数表达的,这两个查询产生非常不同的代数。我使用Apache Jena项目提供的SPARQL Query Validator(免责声明 - 我是该项目的提交者)来生成代数。

您的第一个查询生成以下代数:

(base <http://example/base/>
  (prefix ((ab: <http://learningsparql.com/ns/addressbook#>))
    (project (?first ?last)
      (leftjoin
        (leftjoin
          (bgp (triple ?s ab:lastName ?last))
          (bgp (triple ?s ab:nick ?first)))
        (bgp (triple ?s ab:firstName ?first))))))

您的第二个查询会产生以下代数式:

(base <http://example/base/>
  (prefix ((ab: <http://learningsparql.com/ns/addressbook#>))
    (project (?first ?last)
      (join
        (leftjoin
          (leftjoin
            (table unit)
            (bgp (triple ?s ab:nick ?first)))
          (bgp (triple ?s ab:firstName ?first)))
        (bgp (triple ?s ab:lastName ?last))))))

如您所见,您查询中的三元模式出现顺序不同且运算符也不同。重要的是,您的第二个查询使用了一个 join,它仅保留两边兼容的解决方案,而第一个查询仅使用 leftjoin,如果没有兼容的解决方案,则保留LHS解决方案。
因此,在第一个查询中,您首先找到具有 ab:lastName 的事物,然后在存在时可选添加 ab:nickab:firstName,因此您会返回数据中的所有人。
在第二个查询中,您首先找到具有 ab:nick 的事物,然后在要求一切都具有 ab:lastName 之前,可选添加具有 ab:firstName 的事物。因此,您只能返回具有姓氏的人。

我认为SPARQL查询中的句号与 "and" 运算符相同。

不,它仅终止三元模式,并可以选择跟随其他子句(但不必这样做),它不是 "and" 运算符。
相邻的基本图形模式会被连接起来,除非存在一个替代连接运算符(例如leftjoinminus),这是由OPTIONALMINUS子句的存在所暗示的。
编辑 - 什么是table unittable unit是一种特殊运算符,对应于SPARQL查询中的空图形模式。
例如,SELECT * WHERE { }将产生代数表达式(table unit)
它产生一个单独的空行,在SPARQL语义中意味着它可以与任何内容连接,并返回其他内容,因此实质上它像一个连接标识。在许多情况下,SPARQL引擎可以简化代数以删除table unit,因为在大多数情况下,它对查询的语义没有影响。
在您的第一个查询中,技术上还有另一个join操作符与table unit之间的连接,但在正常连接的情况下,table unit的存在不会产生影响(因为它是连接标识),因此可以并且已经被简化掉了。
然而,对于可选项,SPARQL规范要求所生成的代数是前面子句内部与前置子句左联接的结果。在您的第二个查询中,在第一个“OPTIONAL”之前没有前置子句(技术上说,这里有一个隐含的空图案),因此生成的第一个“leftjoin”将“表单位”放在其左侧。与普通的“join”不同,“表单位”在这种情况下必须被保留,因为“leftjoin”的语义表明,如果RHS没有兼容的解,则会保留LHS的结果。
我们可以通过更简单的查询进行说明:
SELECT *
WHERE
{
  OPTIONAL { ?s a ?type }
}

产生代数式:
(base <http://example/base/>
  (leftjoin
    (table unit)
    (bgp (triple ?s <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ?type))))

9

这个问题很旧,但是答案仍然不太容易清楚地理解。让我来用自然英语尝试一下,感谢SPARQL_Order_Matters的帮助。

当OPTIONALS出现在查询的开头时,它们要么:

  • 没有匹配,什么也不会发生;
  • 匹配,此时它是其余查询必须匹配的起始数据集合。

当OPTIONALS出现在某条语句已经匹配了一些数据之后时,它们要么:

  • 没有匹配,什么也不会发生;
  • 匹配,此时一些新的三元组将被添加到结果中。

所以当一个OPTIONAL首先出现并且它匹配一些三元组时,真正不明显的行为就发生了。这时候所有的查询结果将与该 OPTIONAL 的内容相匹配。


哇,非常感谢!你发布的那个“SPARQL Order Matters”链接确实澄清了很多事情。 - fthinker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接