Как я могу перечислить все остановки, связанные с маршрутом, используя GTFS?

Я работаю с некоторыми данными GTFS и хотел бы иметь возможность создать список всех остановок, связанных с маршрутом. Я не очень понимаю, что делать с данными GTFS.

Trips.txt поставляется в таком формате:

route_id,service_id,trip_id,trip_headsign,direction_id,block_id,shape_id 1,A20120610WKD,A20120610WKD_000800_1..S03R,SOUTH FERRY,1,,1..S03R 1,A20120610WKD,A20120610WKD_002700_1..S03R,SOUTH FERRY,1,,1..S03R 1,A20120610WKD,A20120610WKD_004700_1..S03R,SOUTH FERRY,1,,1..S03R 1,A20120610WKD,A20120610WKD_006700_1..S03R,SOUTH FERRY,1,,1..S03R 1,A20120610WKD,A20120610WKD_008700_1..S03R,SOUTH FERRY,1,,1..S03R

Я пытался читать в соответствующей форме, используя shape_id, а затем искал остановки с соответствующими широтами и долготами, но это не работает надежно. Кто-нибудь знает, как это сделать?

5 ответов

Решение

Как вы заметили, в GTFS нет прямой связи между маршрутами и остановками. Вместо этого остановки связаны с поездками, где каждая поездка представляет собой один "пробег" транспортного средства по определенному маршруту. Это отражает тот факт, что маршрут не обязательно всегда обслуживает каждую из его остановок - например, в выходные дни он может пропускать остановки за пределами средней школы.

Таким образом, получение списка каждой остановки, обслуживаемой маршрутом, предполагает объединение нескольких моделей:

  • routes.txt дает вам идентификатор маршрута для интересующего вас маршрута.
  • trips.txt дает вам набор идентификаторов поездки для этого маршрута.
  • stop_times.txt дает вам набор идентификаторов остановок для остановок, обслуживаемых в каждой из этих поездок.
  • stops.txt дает вам информацию о каждой из этих остановок.

Предполагая, что вы используете базу данных SQL для хранения данных GTFS, вы можете использовать такой запрос (как только вы получите идентификатор маршрута):

SELECT stop_id, stop_name FROM stops WHERE stop_id IN (
  SELECT DISTINCT stop_id FROM stop_times WHERE trip_id IN (
    SELECT trip_id FROM trips WHERE route_id = <route_id>));

Помните, однако, что это выведет запись для каждой остановки, которая когда-либо обслуживается маршрутом. Если вы генерируете информацию о расписании для гонщика, вы, вероятно, захотите ограничить запрос только поездками, выполняемыми сегодня, и только временем остановок с вылетами, скажем, в следующие тридцать минут.


Обновление: я написал вышеупомянутый SQL-запрос так, как я делал, так как я чувствовал, что он наиболее просто проиллюстрировал взаимосвязь между моделями GTFS, но btse правильно (в его ответе ниже), что подобный запрос фактически никогда не будет использоваться в производстве. Это слишком медленно. Вместо этого вы должны использовать объединения таблиц и индексы, чтобы поддерживать разумное время запросов.

Вот эквивалентный запрос, написанный более подходящим для копирования и вставки в реальное приложение:

SELECT DISTINCT stops.stop_id, stops.stop_name
  FROM trips
  INNER JOIN stop_times ON stop_times.trip_id = trips.trip_id
  INNER JOIN stops ON stops.stop_id = stop_times.stop_id
  WHERE route_id = <route_id>;

Обычно вы также создаете индекс для каждого столбца, используемого в JOIN или же WHERE пункт, который в данном случае будет означать:

CREATE INDEX stop_times_trip_id_index ON stop_times(trip_id);

CREATE INDEX trips_route_id_index ON trips(route_id);

(Обратите внимание, что СУБД обычно индексируют каждую таблицу по первичному ключу автоматически, поэтому нет необходимости явно создавать индекс для stops.stop_id.)

Возможны многие дальнейшие оптимизации, в зависимости от конкретной используемой СУБД и вашей готовности жертвовать дисковым пространством для производительности. Но эти команды приведут к хорошей производительности практически в любой СУБД без потери четкости.

Я наткнулся на этот пост в своих поисках в Google и решил, что обновлю его лучше, если кто-нибудь еще наткнется на него. Ответ, который дал Саймон, является на 100% правильным, однако его запрос довольно медленный для больших каналов GTFS. Вот запрос, который делает то же самое, но работает значительно быстрее.

Просто для того, чтобы дать вам некоторые неподтвержденные доказательства, для потока GTFS размером около 50 Мб, запрос Саймона занял где-то от 10-25 секунд. Утверждение ниже занимает последовательно < 0,2 секунды.

SELECT T3.stop_id, T3.stop_name 
FROM trips AS T1
JOIN
stop_times AS T2
ON T1.trip_id=T2.trip_id AND route_id = <routeid>
JOIN stops AS T3
ON T2.stop_id=T3.stop_id
GROUP BY T3.stop_id, T3.stop_name

ОБНОВИТЬ:

Я понял, что не упоминал об этом раньше, но, конечно, вы захотите иметь индексы, где объединяются все таблицы.

Если ты GROUP BY shape_id при выборе из trips Вы можете сделать запрос еще быстрее.

Использование запроса @btse для получения уникальных остановок для двух маршрутов занимает 1,147 с.

Мой эквивалентный запрос занимает 0,4 с.

SELECT unique_stops.route_id, unique_stops.stop_id, stop_name, stop_desc, stop_lat, stop_lon
FROM
  stops,
  (SELECT stop_id, route_id
   FROM
     stop_times,
     (SELECT trip_id, route_id
      FROM trips
      WHERE route_id IN (801, 803)
      GROUP BY shape_id
     ) AS unique_trips
   WHERE stop_times.trip_id = unique_trips.trip_id
   GROUP BY stop_id) AS unique_stops
WHERE stops.stop_id = unique_stops.stop_id

Если вы работаете в R, вы можете сделать это, чтобы найти маршруты, которые останавливаются в вашем пункте назначения X:

require(dplyr)

routesX <- routes %>%
  left_join(trips %>% select(trip_id, route_id, shape_id)) %>%
  left_join(stop_times %>% select(trip_id, stop_id)) %>%
  semi_join(stops %>% filter(grepl('X', stop_name, ignore.case = T)), by = c('stop_id' = 'stop_code')) %>%
  select(names(routes), shape_id) %>%
  unique 

Если необходимо направление остановки, следует изменить ответ Лукмаана:

SELECT unique_stops.route_id, unique_stops.stop_id, stop_name, stop_desc, stop_lat, stop_lon, unique_stops.direction_id
FROM
  stops,
  (SELECT stop_id, route_id, direction_id
   FROM
     stop_times,
     (SELECT trip_id, route_id, direction_id
      FROM trips
      WHERE route_id IN (801, 803)
      GROUP BY direction_id
     ) AS unique_trips
   WHERE stop_times.trip_id = unique_trips.id
   GROUP BY stop_id, direction_id) AS unique_stops
WHERE stops.stop_id = unique_stops.stop_id

Если вы добавите также stop_times.stop_sequence Таким же образом, упорядочивая по направлению и stop_sequence, остановки будут отсортированы так, как они есть в поездке.

Если вы используете "onebusaway", есть быстрый способ сделать это, не касаясь GTFS

Допустим, вы хотите знать, автобусные остановки для автобусного маршрута "M1" в Манхэттене, Нью-Йорк

http://bustime.mta.info/api/where/stops-for-route/MTA%20NYCT_M1.json?key=yourapikey&includePolylines=false&version=2

даст вам json feed, после чего вы сможете извлечь автобусные остановки для обоих направлений на маршруте M1.

Другие вопросы по тегам