如何避免Cypher中两个OPTIONAL MATCH导致结果相乘?
问题原因
你遇到的35是笛卡尔积导致的结果:两个OPTIONAL MATCH会把7条LIKED关系和5条DISLIKED关系两两组合,生成7×5=35条记录。count(l)和count(d)会统计所有组合中的非空值,所以最终两个计数都变成了35。
修正方案
以下几种方法可以避免笛卡尔积,得到正确的计数:
方案1:单MATCH+CASE条件统计
通过一次匹配覆盖两种关系类型,再用条件判断分别计数:
OPTIONAL MATCH (:User)-[r:LIKED|:DISLIKED]->(:User {username: $username}) RETURN count(CASE WHEN type(r) = 'LIKED' THEN 1 END) AS likeCount, count(CASE WHEN type(r) = 'DISLIKED' THEN 1 END) AS dislikeCount
原理:CASE语句仅对符合类型的关系返回1,否则返回NULL;而count()会自动忽略NULL值,从而得到两种关系的真实数量。
方案2:分步聚合统计
先统计一种关系的数量,再基于该结果统计另一种,避免多对多的笛卡尔积:
OPTIONAL MATCH (:User)-[l:LIKED]->(:User {username: $username}) WITH count(l) AS likeCount OPTIONAL MATCH (:User)-[d:DISLIKED]->(:User {username: $username}) RETURN likeCount, count(d) AS dislikeCount
原理:第一个MATCH聚合后仅返回一行结果(likeCount),第二个MATCH的结果只会和这一行组合,不会产生重复计数。
方案3:子查询独立统计
用子查询分别执行两种关系的统计,结果互不干扰:
RETURN (OPTIONAL MATCH (:User)-[l:LIKED]->(:User {username: $username}) RETURN count(l)) AS likeCount, (OPTIONAL MATCH (:User)-[d:DISLIKED]->(:User {username: $username}) RETURN count(d)) AS dislikeCount
原理:两个子查询独立运行,各自计算对应关系的数量,最终合并返回结果。
内容的提问来源于stack exchange,提问作者Audrin
相关产品推荐
相关产品推荐

