SPARQL 代数:根据节点的三元组排除节点

SPARQL algebra: Excluding nodes based on triples they have

看这张图:

:thing1 a :Foo ;
    :has :A ;
    :has :B .

:thing2 a :Foo ;
    :has :B ;
    :has :A .

:thing3 a :Foo ;
    :has :A ;
    :has :B ;
    :has :C .

我想 select :thing1:thing2,但 不是 :thing3

这是我编写的有效的 SPARQL 查询。有更好的方法吗?

SELECT ?foo WHERE {
    ?foo a :Foo ;
        :has :A ;
        :has :B .
    MINUS {
        ?foo a :Foo ;
            :has :A ;
            :has :B ;
            :has ?anythingElse .
        FILTER(?anythingElse != :A && ?anythingElse != :B)
    }
}

您可以使用 NOT IN 运算符而不是布尔表达式来执行此操作,如果您将 MINUS 子句替换为 FILTER NOT EXISTS 子句:

SELECT ?foo WHERE {
    ?foo a :Foo ;
        :has :A, :B .
    FILTER NOT EXISTS {
       ?foo :has ?other .
       FILTER (?other NOT IN (:A, :B))
    }
}

我怀疑性能会有显着差异,但查询更短且更易于阅读。

MINUS 的替代方法是 FILTER NOT EXISTS:

SELECT ?foo WHERE {
    ?foo a :Foo ;
        :has :A, :B .
   FILTER NOT EXISTS {
       ?foo :has ?other .
       FILTER (?other NOT IN (:A, :B))
    }
}

粗略地说,找到所有带有 :A 和 :B 的 ?foo,然后检查它们是否没有其他 : 值。

在执行效率方面,有一些优化可以将一些 MINUS 模式变成 FILTER NOT EXISTS,反之亦然,也有可能共享公共子模式。

如果没有那么聪明的优化器,则 FILTER NOT EXISTS 可能会更快,因为“?foo a :Foo ; ;has :A, :B 。”不重复并且 FILTER 只考虑已经通过“?foo a :Foo ; ;has :A, :B .”的项目。

只有一种方法可以知道哪种方法是当所有效果(包括缓存)结合在一起时在真实数据上进行真实尝试。