如何用Datalog正确查询数据库中不是Milhouse好友的所有人员?
如何用Datalog查询所有不是Milhouse好友的人员?
我们有一个存储人员及好友关系的数据库,数据示例如下:
['"Bart" :person/friend "Milhouse"] ['"Bart" :person/friend "Homer"] ['"Homer" :person/friend "Marge"] ...
需求是获取所有不是Milhouse好友的人员——也就是从未和Milhouse建立好友关系的人,但你之前的查询返回的是"至少有一个好友不是Milhouse"的人员,不符合预期。
问题原因
你之前的查询存在两个核心问题:
- 变量不统一:
:find ?person但:where中使用的是?p,导致目标变量未正确绑定; - 否定逻辑错误:
(not [?p :person/friend ?f] [?f :person/name "Milhouse"])的逻辑是"不存在某个好友叫Milhouse",但只要用户有一个好友不是Milhouse,这个条件就会成立,无法过滤掉那些同时拥有Milhouse和其他好友的人。
正确查询写法
根据你的数据模型(好友直接存储为字符串名称),可以用not-exists来精准检查人员是否存在与Milhouse的好友关系:
(d/q '[:find ?person :where ;; 绑定所有人员实体(确保查询对象是人员) [?person :person/name ?name] ;; 否定该人员与Milhouse存在好友关系记录 (not-exists [?person :person/friend "Milhouse"]) ] db)
如果你的数据模型中好友是指向人员实体(而非直接存储名称),则调整为:
(d/q '[:find ?person :where [?person :person/name ?person-name] ;; 定位Milhouse的实体 [?milhouse :person/name "Milhouse"] ;; 否定该人员与Milhouse的好友关系 (not-exists [?person :person/friend ?milhouse]) ] db)
逻辑说明
not-exists会检查数据库中是否存在满足括号内所有模式的记录:
- 对每个人员
?person,验证是否存在[?person :person/friend "Milhouse"](或实体版本的对应记录); - 只有完全不存在该记录的人员,才会被纳入查询结果,正好符合"不是Milhouse好友"的需求。
内容的提问来源于stack exchange,提问作者adrian n
相关产品推荐
相关产品推荐

