Modeling Neo4j Bus Routing Applications
My question: I have one graph with many nodes representing bus stops. How to include bus information such as which buses are available between nodes.
I am thinking of creating a link between nodes that will have information about all buses between two nodes, as well as a distance value between two stops.
buses[500A,182A],distance:500m buses[121B,542W,222A,111Z],distance:400m
Like A --------------------------------------------- --- -------> B -------------------------------------- --- ------------------> C
So how do I know the bus or buses (if there is no direct route) to get to M from A?
First I find out the path (neo4j request) how to get to M from A.
Tell me my way
buses[11A],distance:1000m buses[11A],distance:250m buses[13B,100A],distance:2000m
a -----------------------------------------> L --- --- -----------------------------> H ---------------- --- ------------------------> M
The problem is how to programmatically check if a direct bus is available in M ββor not, or how to change between the bus in between.
According to the above scenario, I can go from A to N via 11A, then from N to M, taking either 13B or 100A.
I have to do this programmatically.
I want to get all the possible paths between two stations and the total path distance along with the bus information.
source to share
Your model should be more graphical. That is, I do not think that you should have an array property on communication between Stop nodes with bus information. Rather, buses should be the nodes themselves, with an attitude to indicate which stops they stop at. Consider the following data examples:
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 is easy to find a route that minimizes the number of transmissions and also returns all the necessary transmission information, if applicable. For example, all the shortest routes (shortest in terms of the number 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, all of which have the same transmission:
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
You can of course return this information, but you want with a function EXTRACT()
.
Another example. Find a route 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 transmissions:
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
source to share
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 can do something like:
<somehow MATCH on A and B>
CREATE B-[:connects_to {bus: '180Q'}]->A
CREATE B-[:connects_to {bus: '171B'}]->A
etc.
This 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
To be honest, I've never used relationship property matching at the same time as the variable length spec, but I figure it would work
source to share
I have tried all cypher queries but cannot get what I am looking for, bus swap information. So far my request.
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'm having a hard time getting information about the exchange bus.I think I should be doing it programatically.It doesn't look very complicated, but I thought if I can get it from Cypher the request myself.
source to share