Ответ 1
Как вы заметили, нет прямой связи между маршрутами и остановками в 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);
(Обратите внимание, что RDBMSs автоматически индексируют каждую таблицу по ее первичному ключу автоматически, поэтому нет необходимости явно создавать индекс на stops.stop_id
.)
Возможны многие дополнительные оптимизации, в зависимости от конкретной используемой СУБД и вашей готовности жертвовать дисковым пространством для повышения производительности. Но эти команды приносят хорошую производительность практически на любую РСУБД без лишнего пожертвования ясностью.