考虑到它们在路由中出现的顺序,在 neo4j 中获取间接路由

Getting indirect routes in neo4j considering the order in which they appear in a route

所以我试图在由停止节点和路由节点组成的 neo4j 图中获取间接路由。

这是我的关系数据库的 ER 图。

我的模型由停止节点组成,节点具有每个停止点的名称(图片中的蓝色节点)。

我有多条路线与停止节点有关系(STOPS_AT)。这些关系指向公共汽车在沿着特定路线行驶时将停靠的各个站点。

Stops at 关系具有以下属性。

fare_bt_stops - 包含本站与上一站之间的行程票价。 order - 公交车停靠的顺序。原点为 0

这就是我的 STOPS_AT 关系的样子。

所以为了获得 A 到 C 之间的最短距离,我 运行 这个查询是为了获得 A 和 C 之间的路线。

MATCH (a:Stop {name:'A'}), (d:Stop {name:'C'})
MATCH p = allShortestPaths((a)-[:STOPS_AT*..12]-(d))
RETURN EXTRACT(x IN NODES(p) | CASE WHEN x:Stop THEN 'Stop ' + x.name
                                    WHEN x:Route THEN 'Route ' + x.name
                                    ELSE '' END) AS itinerary

给出输出 [Stop 12, Route 4, Stop 13, Route 5, Stop 14]

但是我如何查询这个模型以获得票价最少的路径。我看过其他示例,但在这些示例中,节点是直接连接的,而在我的示例中,它们是通过 Route 节点连接的。

此外,我如何根据 stop_order 属性 验证路线,例如路线 A to B 先停在 A 然后停在 B,而路线 C to B 停在首先是 C,然后是 B,因此不应该有任何方法可以从 A 到达 C,但此查询也没有处理这种特殊情况。所以现在我正在我的代码中处理它,我认为这不是最好的方法。

过去两天我一直坚持这个问题,所以非常感谢我能得到的任何帮助。

问题中的型号信息不足,无法回答票价部分。

关于顺序问题,如果Route有方向,那么它与Stops的关系也应该有方向:

(c:Stop {name: 'C'})-[:STOPS_AT]->(c_to_b:Route)-[:STOPS_AT]->(b:Stop {name: 'B'})

除了关系类型现在没有意义,您可以改为使用 2 种不同的类型:

(c:Stop {name: 'C'})-[:IS_ORIGIN]->(c_to_b:Route)-[:IS_DESTINATION]->(b:Stop {name: 'B'})

现在,如果您沿同一方向跟随这两种类型,您将遵循实际路线(如果存在):

MATCH p = allShortestPaths((a)-[:IS_ORIGIN|IS_DESTINATION*..12]->(d))

在我看来,您过于依赖关系数据库中的表格建模。您正在使用 Neo4j,因此您将不得不考虑将表格模型转换为建模良好并允许在图形模型中进行丰富查询的最佳方法。在这种转换中,关系数据库中的大部分管道都不需要,而且一开始很难识别和看到。

您可能想要改造它的一种方法是删除中间节点,而是简单地使用每个站点之间的关系

因此,例如,如果我们将路线分类为具有相同编号的 :Route 关系的路径,则可以相当轻松地创建路线。它可能建模如下:

(:Bus{ID:1, color:"green", number:"5"})-[:AssignedTo]->(:BusRoute{number:1}, departureTime:xxx})-[:Start]->(:Stop{name:"a"})-[:Route{number:1, fare:"10", duration:"20"]->(:Stop{name:"b"})-[:Route{number:1, fare:"20", duration:"30", finalStop:true}]->(:Stop{name:"d"})

(:Bus{ID:2, color:"red", number:"7"})-[:AssignedTo]->(:BusRoute{number:2}, departureTime:xxx})-[:Start]->(:Stop{name:"d"})-[:Route{number:2, fare:"10", duration:"20"]->(:Stop{name:"c"})-[:Route{number:2 fare:"20", duration:"30"}]->(:Stop{name:"b"}) ...

这使您的路线清晰明了。另请注意,分配给路线的 :Bus 清晰且易于更改,因为巴士与路线的关联位于一个地方。

查找路线 1 的路线,例如将使用如下查询:

MATCH (bus:Bus)-[:AssignedTo]->(busRoute:BusRoute)-[:Start]->(first:Stop)
WHERE busRoute.number = 1
WITH bus, busRoute, first
MATCH (first)-[r:Route*]->(:Stop)
WHERE ALL(route in r | route.number = br.number)
AND LAST(r).finalStop = true
RETURN bus, busRoute, NODES(r) as stops

对于从任何站点到任何其他站点的最短路径的查询,以票价作为权重,您可以自己使用 Cypher 执行此操作,也可以使用 APOC 过程调用为您执行此操作。

首先,简单的方法。如果你安装了APOC Procedures library,你可以这样查询:

MATCH (here:Stop), (destination:Stop)
WHERE here.name = xxx AND destination.name = xxx
WITH here, destination
CALL apoc.algo.dijkstra(here, destination, 'Route>', 'fare') YIELD path, weight
RETURN RELS(path) as rides, weight as cost

如果你想自己做,你可以这样做(给你的可变路径深度添加一个理智的限制)

MATCH (here:Stop), (destination:Stop)
WHERE here.name = xxx AND destination.name = xxx
WITH here, destination
MATCH (here)-[rides:Route*..12]->(destination)
WITH rides, REDUCE(cost = 0, ride in rides | cost + ride.fare) AS cost
ORDER BY cost ASC LIMIT 1
RETURN rides, cost