用逻辑降维打击 SPARQL 查询:无痛写 NOT EXISTS (7)
内容预告
在编写查询时,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
有一个儿子一个女儿:
逻辑基础
使用自然语言表达直接写查询可能会显得笨拙而且不好理解。但如果我们转换成逻辑语言,表达就会更加流畅。以下是一些基本的逻辑公式:
命题逻辑:
蕴含
(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
不是没有孩子的吗?怎么也被检索出来了???
分析下为啥跟预期的结果不一样
可以确定的是,最后的逻辑表达式一定等价于原命题,那我们来看一眼原命题:$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
)。此外,任何一个有女儿的人都会被查出来,结果是这样的
之前的文章
知识图谱 (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 这个网页自行尝试
参考
- Scientific Data Management & Knowledge Graph, by Maria-Esther Vidal
- https://rdfplayground.dcc.uchile.cl
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· 单线程的Redis速度为什么快?
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码