我正在处理一些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读取匹配的形状,然后寻找纬度和经度匹配的站点,但这似乎不可靠。有人知道怎么做吗?
正如您所注意到的,GTFS中的路线和站点之间没有直接的关系。相反,停靠与行程相关,其中每次行程代表车辆沿特定路线的一次"运行"。这反映了这样一个事实,即一条路线不一定总是为每一站服务;例如,在周末,它可能会跳过高中外的站点。
因此,要获得一条路线所服务的每一站的列表,需要结合几种模型:
routes.txt
会为您提供感兴趣的路线的路线IDtrips.txt
会为您提供该路线的一组行程IDstop_times.txt
为您提供了一组站点ID,用于每次出行的站点stops.txt
会为您提供有关这些站点的信息
假设您使用SQL数据库来存储GTFS数据,您可能会使用这样的查询(一旦您获得了路由ID):
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);
(请注意,RDBMS通常会自动通过主键为每个表建立索引,因此不需要在stops.stop_id
上显式创建索引。)
许多进一步的优化是可能的,这取决于所使用的特定DBMS以及您是否愿意牺牲磁盘空间来提高性能。但这些命令在几乎任何RDBMS上都会产生良好的性能,而不会不必要地牺牲清晰度。
我在谷歌搜索中发现了这篇文章,我想我会用一个更好的答案来更新它,以防其他人偶然发现它。Simon给出的答案是100%正确的,然而,他提供的查询对于大型GTFS提要来说相当慢。这是一个执行相同操作的查询,但执行的速度明显快。
为了给你一些轶事证据,对于大约50mb的GTFS提要,Simon的查询需要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
更新:
我意识到我以前没有提到这一点,但当然,您会希望在每个表连接的地方都有索引。
如果从trips
中选择GROUP BY shape_id
,则可以使查询速度更快。
使用@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
如果需要停止的方向,则应更改Lukmaan的答案:
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&版本=2
会给你一个json提要,然后你可以提取M1路线上两个方向的公交车站。