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

时间:2016-09-22 10:42:32

标签: graph neo4j shortest-path

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

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

enter image description here

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

我有多条路径与停止节点有关系(STOPS_AT)。这些关系指向公共汽车在特定航线之后将会产生的各种停靠点。

Stops at relationship具有以下属性。

fare_bt_stops - 它有这个站点和前一站点之间的票价。 订单 - 停靠巴士的订单。原点是0

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

enter image description here

enter image description here

因此,要获得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的任何方式,但此查询也不处理此特定情况。所以现在我在我的代码中处理它,我认为这不是最好的方法。

过去两天我一直坚持这一点,所以我将不胜感激任何帮助。

2 个答案:

答案 0 :(得分:2)

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

您可能想要重新构建的一种方法是删除中间节点,而只是使用每个停靠点之间的关系

因此,例如,如果我们将路线分类为以下路径:使用相同数字的路线关系,您可以非常轻松地创建路线。它可能会模仿这样的东西:

(: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"}) ...

这使您的路线清晰明确。另请注意:分配给路线的公交车是清晰的,并且很容易更改,因为公交车与路线的关联在一个地方。

例如,查找路径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

答案 1 :(得分:0)

问题中的模型信息不足以回答票价部分。

关于订单问题,如果Route有方向,那么它与Stops的关系也是如此:

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

除了关系类型现在没有意义,你可以使用两种不同的类型:

(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))