用逻辑降维打击 SPARQL 查询:无痛写 NOT EXISTS (7)

发布时间 2024-01-05 08:51:26作者: JasonHao

内容预告

在编写查询时,NOT EXISTS往往是最反直觉且难以理解的部分。
本文将分享如何清晰且轻松地掌握SPARQL中的NOT EXISTS查询方法,这些技巧同样适用于其他查询语言。

查询语言为什么设计了个这么奇怪的 NOT EXISTS?

用于表达否定:用于表达不满足某些条件的情况。例如,查询非O型血的人:

SELECT ?person WHERE{
?person a ex:Person . 
FILTER NOT EXITSTS {?person ex:bloodType "O"^^xsd:string}
}

处理空值:例如,查询没有女朋友的人:

SELECT ?person WHERE{
?person a ex:Person . 
FILTER NOT EXISTS {?person ex:girlFriend ?gf}
}

表达全称量词:例如,查询所有孩子都是女儿的人:
过去老师教我们的方法,直接用嘴说:“不存在这样的人,他孩子不是女儿”。

SELECT ?parent WHERE{
?person a ex:Person . 
?parent ex:hasChild ?child . 
FILTER NOT EXISTS {?parent ex:hasChild ?child1. 
			    ?child1 ex:sex ?sex . 
			    FILTER(?sex != "W")}
}

查询是写出来了,但说的像人话吗?听不懂,很反直觉。

查询结果只有 ex:p1 满足。ex:p2 没有孩子,ex:p3有个儿子,ex:p4有一个儿子一个女儿: image.png

逻辑基础

使用自然语言表达直接写查询可能会显得笨拙而且不好理解。但如果我们转换成逻辑语言,表达就会更加流畅。以下是一些基本的逻辑公式:
命题逻辑

  • 蕴含 (Implication):$(p\rightarrow q) \equiv (\neg p\lor q)$ (只有 $p$ 为 True 并且 $q$ 为 False 的时候 $p\rightarrow q$ 为假).
  • 双重否定:$\neg \neg p \equiv p$.
  • 摩根定律 (De Mogen's Law): $\neg(p\land q)\equiv (\neg p \lor \neg q)$ 和 $\neg(p\lor q)\equiv (\neg p\land \neg q)$. 举个例子,"鱼与熊掌不可兼得": $\neg(有?\land 有?)\equiv (\neg ?\lor \neg ?)$ 等价于 "没有?或者没有?".
    谓词逻辑
  • 全称量词否定:$\neg(\forall x)[f(x,y)]\equiv (\exists x)[\neg f(x,y)]$ (不是所有的 $x$ 都有谓词 $f(x,y)$,等同于存在某个 $x$ 没有谓词 $f(x,y)$).

无痛写查询 () 步骤:

1.查询的自然语言表达。“查询孩子都是女儿的人”: 我们要查找这样的人:如果他有孩子,那么这个孩子一定是女儿.
2.自然语言转逻辑语言。${p|Person(p)\land (\forall c)[(hasChild(p,c)\rightarrow hasSex(c,$"W"$))]}$
3.逻辑语言变换。因为 SPARQL 没有全称量词表达,只能表达存在量词 (也就是 FILTER NOT EXISTS)。这里需要把 $\forall c$ 用 $\not\exists c$ 表达:

  • 把条件改用双重否定 $Person(p)\land \neg\neg(\forall c)[hasChild(p,c)\rightarrow hasSex(c,$"W"$)]$
  • 将第二个否定用全称量词否定得到 $Person(p)\land \neg(\exists c)[\neg (hasChild(p,c)\rightarrow hasSex(c,$"W"$))]$ 这里只对
  • 蕴含改用逻辑 得到 $Person(p)\land \neg(\exists c)[\neg (\neg hasChild(p,c)\lor hasSex(c,$"W"$))]$
  • 使用 摩根定律 化掉括号外的否定 $\neg$ 得到 $Person(p)\land \neg(\exists c)[(hasChild(p,c)\land \neg hasSex(c,$"W"$))]$
  • 使用 $\not \exists$ 得到 $Person(p)\land (\not\exists c)[(hasChild(p,c)\land \neg hasSex(c,$"W"$))]$,此时连接词都要是 $\land$,因为 SPARQL 所有的子句都是用逻辑 (.) 连接的。
    4.对照着写 SPARQL
SELECT ?p WHERE{
?p a ex:Person . 
FILTER NOT EXISTS {?p ex:hasChild ?c . ?c ex:sex ?sex . FILTER (?sex != "W")}
}

跑出来的结果竟然还多了个 ex:p2,什么鬼?ex:p2不是没有孩子的吗?怎么也被检索出来了???
image.png

分析下为啥跟预期的结果不一样

可以确定的是,最后的逻辑表达式一定等价于原命题,那我们来看一眼原命题:$Person(p)\land (\forall c)[(hasChild(p,c)\rightarrow hasSex(c,$"W"$))]}$,ex:p2 肯定满足 $Person(p)$,那满足 $(\forall c)[(hasChild(p,c)\rightarrow hasSex(c,$"W"$))]}$ 吗?满足!因为ex:p2没有孩子,此时前件 $hasChild(p,c)$ 为假,蕴含 中假推出任何布尔值都为真!

又来举例子:
(1) “如果我有一个亿,那么我和马斯克就是兄弟”,这句话是真的,假推出假为真。
(2) “如果我有一个亿,那么我就有一张嘴”,这句话也是真的,假推出真也为真。
逻辑就是这么神奇,逻辑就是这么反直觉!!!但是它就是真的。

经常不小心就范的错误❌案例

这里有同学可能会表达成 “我们要查找这样的父母,他有孩子并且是女孩儿”,
然后逻辑语言表达成了 ${p|Person(p)\land (\forall c)[hasChild(p,c)\land hasSex(c,$"W"$)]}$
写成了这样的查询:

SELECT ?p WHERE{
?p a ex:Person .
?p ex:hasChild ?c .
?c ex:sex "W"
}

这里的查询不对:☝?因为查询没有表达全称量词 $\forall c$ (也就是使用 FILTER NOT EXISTS)。此外,任何一个有女儿的人都会被查出来,结果是这样的
image.png

之前的文章

知识图谱 (1)
本体论介绍 (2)
动手构建你的第一个知识图谱 by RDF (3)
图数据模型介绍 (4) 数学符号警告
SPARQL查询:如何高效检索Web数据 (5)
深入探索 SPARQL,复杂查询和聚合函数 (6)

不定期更新专业知识和有趣的东西,欢迎反馈、点赞、加星

您的鼓励和支持是我坚持创作的最大动力!ღ( ´・ᴗ・` )

RDF toy 数据

@prefix ex: <http://example.org/> .

ex:p1 a ex:Person;
      ex:hasChild ex:c1 . 
ex:c1 ex:sex "W".

ex:p2 a ex:Person. 

ex:p3 a ex:Person;
      ex:hasChild ex:c2.
ex:c2 ex:sex "M".

ex:p4 a ex:Person; 
      ex:hasChild ex:c3, ex:c4.
ex:c3 ex:sex "W".
ex:c4 ex:sex "M".

可以到 https://rdfplayground.dcc.uchile.cl 这个网页自行尝试

参考

  1. Scientific Data Management & Knowledge Graph, by Maria-Esther Vidal
  2. https://rdfplayground.dcc.uchile.cl