Neo4j Bus Route Application Modeling

依然范特西╮ 提交于 2019-11-27 13:22:46

Your model needs to be more graphy-y. That is, I don't think you should have an array property on the relationship between Stop nodes with the bus information. Rather, the buses should be nodes themselves with a relationship to indicate which stops they stop at. Consider the following example data:

CREATE (a:Stop {name:'A'}),
       (b:Stop {name:'B'}),
       (c:Stop {name:'C'}),
       (d:Stop {name:'D'}),

       (a)-[:NEXT {distance:1}]->(b),
       (b)-[:NEXT {distance:2}]->(c),
       (c)-[:NEXT {distance:3}]->(d),

       (b1:Bus {id:1}),
       (b2:Bus {id:2}),
       (b3:Bus {id:3}),

       (b1)-[:STOPS_AT]->(a),
       (b1)-[:STOPS_AT]->(b),
       (b2)-[:STOPS_AT]->(a),
       (b2)-[:STOPS_AT]->(b),
       (b2)-[:STOPS_AT]->(c),
       (b3)-[:STOPS_AT]->(b),
       (b3)-[:STOPS_AT]->(c),
       (b3)-[:STOPS_AT]->(d);

The graph now looks like this:

With this model, it's easy to find an itinerary that minimizes the number of transfers and also returns all the necessary transfer information, if applicable. For example, all shortest itineraries (shortest in terms of # of transfers) from A to D:

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

Three routes were found, which all have one transfer:

Stop A, Bus 2, Stop C, Bus 3, Stop D
Stop A, Bus 1, Stop B, Bus 3, Stop D
Stop A, Bus 2, Stop B, Bus 3, Stop D

Of course, you can return this information however you want with the EXTRACT() function.

Another example. Find an itinerary from A to C:

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

One route was found, and there are no transfers:

Stop A, Bus 2, Stop C

Please let me know if this answers your question.

EDIT: To get the distance:

MATCH (a:Stop {name:'A'}), (d:Stop {name:'D'})
MATCH route = allShortestPaths((a)-[:STOPS_AT*]-(d)),
      stops = (a)-[:NEXT*]->(d)
RETURN EXTRACT(x IN NODES(route) | CASE WHEN x:Stop THEN 'Stop ' + x.name
                                        WHEN x:Bus THEN 'Bus ' + x.id
                                   ELSE '' END) AS itinerary,
       REDUCE(d = 0, x IN RELATIONSHIPS(stops) | d + x.distance) AS distance


                           itinerary  distance
Stop A, Bus 1, Stop B, Bus 3, Stop D         6
Stop A, Bus 2, Stop B, Bus 3, Stop D         6
Stop A, Bus 2, Stop C, Bus 3, Stop D         6

Since you can create multiple relationships between the same nodes, I would suggest creating a relationship for each bus. So from your example:

A<-----------------B<-------------------------------C
   buses[180Q,171B]      buses[80A,43B,121S]

You might do something like:

<somehow MATCH on A and B>
CREATE B-[:connects_to {bus: '180Q'}]->A
CREATE B-[:connects_to {bus: '171B'}]->A

and so on...

That way you can do

MATCH path=(start {id: '123'})-[:connects_to {bus: '180Q'}*1..10]-(end: {id: '321'})
UNWIND relationships(path) AS hop
WITH path, hop
WITH path, collect(DISTINCT hop.bus) AS busses
WHERE length(busses) <= 2
RETURN path

Honestly I've never used both a relationship property match at the same time as a variable length specification, but I imagine it would work

I tried quite of cypher queries but can not get what I am looking for, the bus interchange info. Until now my query is.

MATCH (from:Stop { name:"A" }), (to:Stop { name: "S"}) , path = (from)-[:CONNECTED*]->(to)
unwind relationships(path) as hop
RETURN extract(n IN nodes(path)| n.name) AS Shortest_Route,collect(hop.Buses) as Buses,length(path) as Stop_Count,
reduce(distance = 0, r in relationships(path) | distance+r.distance) AS Shortest_Distance
ORDER BY Shortest_Distance ASC
LIMIT 1 .

I am finding it hard to get bus interchange information.I think I have to do it programatically.It does not look very complex , but I was thinking If I can get it from cypher query itself.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!