You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无需Neo4j插件,基于Connection节点求A到C的带权最短路径

无需Neo4j插件实现指定最短路径查询

当然可以做到!不用任何第三方插件,咱们完全可以用Cypher原生的递归查询来实现需求——既基于Connection的cost属性找到从A到C的最短路径,又能完整保留Connection节点与Foo的CONTAINS关系,不会因为转换为关系而丢失这层关联。

核心思路

咱们可以通过逐步扩展路径的方式,每一步记录当前所在的Stop节点、路径包含的所有节点/关系、以及累积的总成本,直到到达目标节点C。最后从所有到达C的路径中筛选出总成本最小的那条即可。

完整Cypher查询示例

// 第一步:初始化路径,从起点A出发获取所有第一跳的路径
MATCH (start:Stop {name: 'A'})
MATCH (start)<-[:BEGINS_AT]-(firstConn:Connection)-[:ENDS_AT]->(nextStop:Stop)
OPTIONAL MATCH (foo:Foo)-[:CONTAINS]->(firstConn)  // 保留Foo与Connection的关联关系
WITH 
  nextStop AS currentStop,
  // 记录路径中的所有节点:起点A、当前Connection、下一站Stop,若有Foo则一并加入
  [start, firstConn, nextStop] + CASE WHEN foo IS NOT NULL THEN [foo] ELSE [] END AS pathNodes,
  // 记录路径中的所有关系:BEGINS_AT、ENDS_AT,若有CONTAINS则一并加入
  [(:BEGINS_AT), (:ENDS_AT)] + CASE WHEN foo IS NOT NULL THEN [(:CONTAINS)] ELSE [] END AS pathRels,
  firstConn.cost AS totalCost
WHERE currentStop.name <> 'C'  // 先排除直接到达C的情况,后续统一处理

// 第二步:递归扩展中间路径,逐步累积
UNION ALL
MATCH (currentStop:Stop)<-[:BEGINS_AT]-(nextConn:Connection)-[:ENDS_AT]->(newStop:Stop)
OPTIONAL MATCH (foo:Foo)-[:CONTAINS]->(nextConn)
WITH 
  currentStop, newStop, nextConn, foo,
  pathNodes, pathRels, totalCost
WHERE NOT newStop IN pathNodes  // 避免路径循环(若允许重复站点可删除此条件)
WITH 
  newStop AS currentStop,
  pathNodes + [nextConn, newStop] + CASE WHEN foo IS NOT NULL THEN [foo] ELSE [] END AS pathNodes,
  pathRels + [(:BEGINS_AT), (:ENDS_AT)] + CASE WHEN foo IS NOT NULL THEN [(:CONTAINS)] ELSE [] END AS pathRels,
  totalCost + nextConn.cost AS totalCost
WHERE currentStop.name <> 'C'

// 第三步:收集所有到达终点C的路径
UNION ALL
MATCH (currentStop:Stop)<-[:BEGINS_AT]-(finalConn:Connection)-[:ENDS_AT]->(end:Stop {name: 'C'})
OPTIONAL MATCH (foo:Foo)-[:CONTAINS]->(finalConn)
WITH 
  currentStop, finalConn, foo,
  pathNodes, pathRels, totalCost
WITH 
  pathNodes + [finalConn, end] + CASE WHEN foo IS NOT NULL THEN [foo] ELSE [] END AS fullPathNodes,
  pathRels + [(:BEGINS_AT), (:ENDS_AT)] + CASE WHEN foo IS NOT NULL THEN [(:CONTAINS)] ELSE [] END AS fullPathRels,
  totalCost + finalConn.cost AS totalCost

// 第四步:筛选出总成本最小的路径
WITH fullPathNodes, fullPathRels, totalCost
ORDER BY totalCost ASC
LIMIT 1
RETURN fullPathNodes AS completePathNodes, fullPathRels AS completePathRels, totalCost AS minimumTotalCost

关键细节说明

  • 递归逻辑:通过UNION ALL拼接初始路径、中间扩展路径和终点路径,实现路径的逐步累积扩展。
  • 保留CONTAINS关系:用OPTIONAL MATCH抓取每个Connection对应的Foo节点和CONTAINS关系,并将其加入路径集合,确保这层关联不会丢失。
  • 避免循环路径:通过WHERE NOT newStop IN pathNodes防止路径出现循环(如果业务允许重复经过同一站点,可以去掉这个条件)。
  • 严格单向性:完全遵循Connection的单向规则,只从BEGINS_AT指向的Stop出发,向ENDS_AT指向的Stop扩展,不会反向遍历。

简化版(若无需显式保留Foo关系)

如果你的需求只关注最短路径的站点序列和总成本,不需要显式输出Foo节点及CONTAINS关系,可以用更简洁的查询:

MATCH (start:Stop {name: 'A'})
// 递归查询所有到达C的有效路径,并计算总成本
CALL {
  WITH start
  MATCH (start)<-[:BEGINS_AT]-(c1:Connection)-[:ENDS_AT]->(s1:Stop)
  OPTIONAL MATCH (s1)<-[:BEGINS_AT]-(c2:Connection)-[:ENDS_AT]->(s2:Stop)
  // 可根据需要继续扩展多跳,或者用递归的方式适配任意跳数
  // 这里用reduce计算总成本,只累加Connection的cost
  WITH 
    [start, c1, s1] + CASE WHEN s2 IS NOT NULL THEN [c2, s2] ELSE [] END AS path,
    reduce(total = 0, conn IN [c1, c2] WHERE conn IS NOT NULL | total + conn.cost) AS totalCost
  WHERE last(nodes(path)).name = 'C'
  RETURN path, totalCost
}
ORDER BY totalCost ASC
LIMIT 1
RETURN path, totalCost

不过这个简化版更适合跳数较少的场景,若要适配任意跳数,还是前面的完整递归查询更可靠。

内容的提问来源于stack exchange,提问作者Erik Hofer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 21:12:40