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.

+3


source to share


3 answers


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:

model

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

      

+8


source


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

0


source


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.

0


source







All Articles