1 | = Advanced usage of pgRouting shortest path search = |
---|
2 | |
---|
3 | An ordinary shortest path query with result usualy looks like this: |
---|
4 | |
---|
5 | {{{ |
---|
6 | SELECT * FROM shortest_path_shooting_star( |
---|
7 | 'SELECT gid as id, source, target, length as cost, x1, y1, x2, y2, rule, |
---|
8 | to_cost, reverse_cost FROM ways', 1955, 5787, true, true); |
---|
9 | |
---|
10 | vertex_id | edge_id | cost |
---|
11 | -----------+---------+--------------------- |
---|
12 | 8134 | 1955 | 0.00952475464810279 |
---|
13 | 5459 | 1956 | 0.0628075563112871 |
---|
14 | 8137 | 1976 | 0.0812786367080268 |
---|
15 | 5453 | 758 | 0.0421747270358272 |
---|
16 | 5456 | 3366 | 0.0104935732514831 |
---|
17 | 11086 | 3367 | 0.113400030221047 |
---|
18 | 4416 | 306 | 0.111600379959229 |
---|
19 | 4419 | 307 | 0.0880411972519595 |
---|
20 | 4422 | 4880 | 0.0208599114366633 |
---|
21 | 5101 | 612 | 0.0906859882381495 |
---|
22 | 5102 | 5787 | 80089.8820919459 |
---|
23 | (11 rows) |
---|
24 | }}} |
---|
25 | |
---|
26 | That is usually called SHORTEST path, which means that a length of an edge is |
---|
27 | its cost. |
---|
28 | |
---|
29 | == Costs can be anything ("Weighted costs") == |
---|
30 | |
---|
31 | But in real networks we have different limitations or preferences for different |
---|
32 | road types for example. In other words, we want to calculate CHEAPEST path - a |
---|
33 | path with a minimal cost. There is no limitation in what we take as costs. |
---|
34 | |
---|
35 | When we convert data from OSM format using the osm2pgrouting tool, we get these |
---|
36 | two additional tables for road types and classes: |
---|
37 | {{{ |
---|
38 | \d classes |
---|
39 | |
---|
40 | id | name |
---|
41 | -----+------------ |
---|
42 | 2 | cycleway |
---|
43 | 1 | highway |
---|
44 | 4 | junction |
---|
45 | 3 | tracktype |
---|
46 | }}} |
---|
47 | |
---|
48 | {{{ |
---|
49 | \d types |
---|
50 | |
---|
51 | id | type_id | name | cost |
---|
52 | -----+---------+--------------------+-------- |
---|
53 | 201 | 2 | lane | 1 |
---|
54 | 204 | 2 | opposite | 1 |
---|
55 | 203 | 2 | opposite_lane | 1 |
---|
56 | 202 | 2 | track | 1 |
---|
57 | 117 | 1 | bridleway | 1 |
---|
58 | 113 | 1 | bus_guideway | 1 |
---|
59 | 118 | 1 | byway | 1 |
---|
60 | 115 | 1 | cicleway | 1 |
---|
61 | 116 | 1 | footway | 1 |
---|
62 | 108 | 1 | living_street | 1 |
---|
63 | 101 | 1 | motorway | 0.2 |
---|
64 | 103 | 1 | motorway_junction | 0.2 |
---|
65 | 102 | 1 | motorway_link | 0.2 |
---|
66 | 114 | 1 | path | 100 |
---|
67 | 111 | 1 | pedestrian | 100 |
---|
68 | 106 | 1 | primary | 100 |
---|
69 | 107 | 1 | primary_link | 100 |
---|
70 | 107 | 1 | residential | 100 |
---|
71 | 100 | 1 | road | 0.7 |
---|
72 | 100 | 1 | unclassified | 0.7 |
---|
73 | 106 | 1 | secondary | 10 |
---|
74 | 109 | 1 | service | 10 |
---|
75 | 112 | 1 | services | 10 |
---|
76 | 119 | 1 | steps | 10 |
---|
77 | 107 | 1 | tertiary | 10 |
---|
78 | 110 | 1 | track | 10 |
---|
79 | 104 | 1 | trunk | 10 |
---|
80 | 105 | 1 | trunk_link | 10 |
---|
81 | 401 | 4 | roundabout | 10 |
---|
82 | 301 | 3 | grade1 | 15 |
---|
83 | 302 | 3 | grade2 | 15 |
---|
84 | 303 | 3 | grade3 | 15 |
---|
85 | 304 | 3 | grade4 | 15 |
---|
86 | 305 | 3 | grade5 | 15 |
---|
87 | }}} |
---|
88 | |
---|
89 | Road class is linked with the ways table by class_id field. Cost values for |
---|
90 | classes table are assigned arbitrary. |
---|
91 | |
---|
92 | {{{ |
---|
93 | UPDATE classes SET cost=15 WHERE id>300; |
---|
94 | }}} |
---|
95 | |
---|
96 | For better performance it is worth to create an index on id field of classes table. |
---|
97 | {{{ |
---|
98 | CREATE INDEX class_idx ON ways (id); |
---|
99 | }}} |
---|
100 | |
---|
101 | The idea behind these two tables is to specify a factor to be multiplied with |
---|
102 | the cost of each link (usually length): |
---|
103 | |
---|
104 | {{{ |
---|
105 | SELECT * FROM shortest_path_shooting_star( |
---|
106 | 'SELECT gid as id, class_id, source, target, length*c.cost as cost, |
---|
107 | x1, y1, x2, y2, rule, to_cost, reverse_cost*c.cost as reverse_cost |
---|
108 | FROM ways w, classes c |
---|
109 | WHERE class_id=c.id', 1955, 5787, true, true); |
---|
110 | vertex_id | edge_id | cost |
---|
111 | -----------+---------+--------------------- |
---|
112 | 8134 | 1955 | 0.00666732825367195 |
---|
113 | 5459 | 1956 | 0.043965289417901 |
---|
114 | 8137 | 1992 | 0.126646230936747 |
---|
115 | 5464 | 762 | 0.827868704808978 |
---|
116 | 5467 | 763 | 0.16765902528648 |
---|
117 | ... | ... | ... |
---|
118 | 9790 | 5785 | 0.00142107468268373 |
---|
119 | 8548 | 5786 | 0.00066608685984761 |
---|
120 | 16214 | 5787 | 0.0160179764183892 |
---|
121 | (69 rows) |
---|
122 | }}} |
---|
123 | |
---|
124 | We can see that the shortest path result is completely different from the |
---|
125 | example before. We call this "weighted costs". |
---|
126 | |
---|
127 | Another example is to restrict access to roads of a certain type: |
---|
128 | {{{ |
---|
129 | UPDATE classes SET cost=100000 WHERE name LIKE 'motorway%'; |
---|
130 | }}} |
---|
131 | |
---|
132 | Through subqueries you can "mix" your costs as you like and this will change |
---|
133 | the results of your routing request immediately. Cost changes will affect the |
---|
134 | next shortest path search, and there is no need to rebuild your network. |
---|