社交图「找好友」功能Cypher查询:按最短路径排序且保留无关联节点
嘿,这个需求很贴合实际场景!我给你准备了两个精准的解决方案,分别对应你提到的两个思路:
方案一:为无关联用户设置默认路径长度(比如20)
你的核心问题是原来的MATCH会过滤掉没有路径的用户,所以我们可以换成OPTIONAL MATCH来保留这些用户,再用COALESCE函数把null的路径长度替换成你想要的默认值(比如20),这样就能让无关联用户排在所有有路径用户的后面。
另外要注意:你原来的WHERE子句存在逻辑优先级问题——AND的优先级比OR高,导致me.user_id='someuserid1234'只会和u.last_name的条件绑定,这会得到错误的结果,我已经在下面的查询里修正了这个问题:
// 先匹配当前用户,避免重复匹配 MATCH (me:User {user_id:'someuserid1234'}) // 匹配所有符合名字条件的用户 MATCH (u:User) WHERE u.first_name =~ '(?i)Bill.*' OR u.last_name =~ '(?i)Bill.*' // 可选匹配最短路径,无路径时path为null OPTIONAL MATCH path=shortestPath((me)-[:WORKED_ON]-(u)) // 用COALESCE把null的路径长度替换成20,再排序 RETURN u, path ORDER BY COALESCE(LENGTH(path), 20) ASC
这个查询会先返回所有和你有路径关联的用户(按路径长度从短到长排序),然后再返回无关联的用户,完美符合你的需求。
方案二:结果数少于X时忽略排序规则
如果想在结果数量较少时(比如少于10条)跳过路径排序,我们可以先用窗口函数统计总结果数,再通过CASE语句动态决定排序规则:
MATCH (me:User {user_id:'someuserid1234'}) MATCH (u:User) WHERE u.first_name =~ '(?i)Bill.*' OR u.last_name =~ '(?i)Bill.*' // 用窗口函数统计符合条件的用户总数 WITH u, me, COUNT(u) OVER() AS total_results OPTIONAL MATCH path=shortestPath((me)-[:WORKED_ON]-(u)) RETURN u, path ORDER BY // 当总数≥X时按路径长度排序,否则按用户名排序(你也可以换成其他规则) CASE WHEN total_results >= 10 THEN COALESCE(LENGTH(path), 20) ELSE u.first_name END ASC
这里的逻辑是:如果搜索到的用户数量≥10,就按方案一的规则排序;如果少于10,就按用户名排序(避免结果太少时排序意义不大)。你可以根据实际需求调整X的值和else分支的排序字段。
内容的提问来源于stack exchange,提问作者Scott
相关产品推荐
相关产品推荐

