GTFSリアルタイムのデータを扱う際に気をつけるべき点
こんにちは、441です。ナビタイムジャパンでバスロケーション機能のバックエンドサーバの開発・運用を担当しています。
GTFSリアルタイムとは
GTFSリアルタイムとは、Protocol Buffers でシリアライズされた形式で公共交通のリアルタイム情報を格納するためのフォーマットです。
各バス会社から配信されており、運行中のバスの位置や車両の混雑具合、遅れの時間などを参照することができます。
そんな GTFSリアルタイムですが、あくまでもフォーマットですのでデータの過不足やその違いで、表現できることが変わってきます。
そこで今回は、実際に取り扱ったことのある違いを何点か紹介しつつ、その違いによってどういった特徴が出るのかをお話させていただきます。
1. 配信内容に違いがあるとき
仕様
GTFSリアルタイムには大きく分けて3つの情報を持つデータ構造体があります。
TripUpdate (ルートの最新情報),
VehiclePosition (車両の現在位置),
Alert (運行情報)
これらのうち、バスロケーション情報をユーザーに届けるにはTripUpdate (ルートの最新情報), VehiclePosition (車両の現在位置)の2つを扱う必要があります。
この2つが揃っている場合に、サービス上でどのようなことができるのか、簡単にですが表にまとめました。
このように、データが揃っている場合は多くの情報をユーザーに提供することができます。
また、国土交通省が定める GTFSリアルタイム のガイドライン では TripUpdate と VehiclePosition の両方配信されることが推奨されています。
一方で Google の定義では、片方のデータだけ配信しても問題ないという仕様になっています。
実際のデータ
そういった仕様の違いがあるため、公開されているオープンデータの中に1割程度ほど、 VehiclePosition のデータのみ配信されているといったケースも存在していました。
気をつけること
この場合、最初にお見せした表にある通り、遅れや到着予測時刻といった時間に関する情報が一切取得できないため、サービス上でも遅れの情報が出せません。
もちろん、バスがどこにいるのかという情報は配信されているため、この情報をユーザーに届けることはできます。
2. 便を特定するとき
仕様
GTFSリアルタイムでは、今走っているバスが何時発の便なのかを特定するためのオブジェクトとして TripUpdate と VehiclePosition の中に TripDescriptor というものが定義されています。
(TripUpdate の場合必須・VehiclePosition の場合任意)
殆どの場合、このオブジェクトのユニークキーは trip_id なのですが、まれに route_id, direction_id, start_date, start_time の4つを指定しないとユニークに特定できないケースがあります。
また、実際に出会ったことは無いですが、特定するためのパターンが他にもあります。そちらについては詳しくは Google のリファレンスを参照ください。
実際のデータ
trip_id でユニークに特定するケースのほうが多かったです。
その中でもごく稀に、当社で扱ったバス会社の中には route_id, direction_id, start_date, start_time の4つを指定するケースがありました。
気をつけること
実装面の話になりますが、1つの系統上を走るバスを特定するとなった場合、この4つの組み合わせをORで検索していく必要があり、検索が少し手間でした。
サービス上で出したい便を決め、GTFSリアルタイムのデータと紐付けができないと、誤った便の情報を出すことになるため、間違いが許されない点であり複数のパターンを考慮しないといけない要素になります。
そのため、便を特定する際には trip_id で特定するケースと route_id, direction_id, start_date, start_time の4つを指定するケースの両方が扱えるようにする必要があります。
3. 走行区間を特定するとき
仕様
どのバス停間を走行中なのかについては 、VehiclePosition に含まれる stop_id (どのバス停を通過したのか), current_stop_sequence (ルート上の何番目のバス停を通過したか) を用いることで表現することができます。
どちらも仕様上は任意の値となっています。
実際のデータ
仕様上は任意のため両方ないケースもありますが、多くの会社ではどちらかの値が入っているため、この値を使うことでルート上のどのバス停間を走行中なのかを特定することが可能です。
後述しますが、どちらの値を利用するかで考慮する内容が変わります。
気をつけること
stop_id 使って特定しようとする場合、同じバス停に2回停車するルートだと、次に止まるバス停が1回目と2回目のどちらのバス停を指すのかがわからなくなります。特定するためには GTFS の他の情報(時刻やバス停の緯度経度等)を用いる必要がありロジックが複雑になります。
一方、current_stop_sequence の場合、純粋にルート上の何番目を走行中なのかを表している値のため、どのバス停間にいるのかを簡単に特定することができます。
また、かなり無理矢理な方法ではありますが、イレギュラーケースとして TripUpdate に含まれる StopTimeUpdate の stop_sequence を使うことで、どのバス停間にバスがいるかを把握することができます。
StopTimeUpdate はかなりパターンがあるため、詳細は次の項目で触れますが、この方法で特定することができるのは通過済みは返却されないパターンの場合に可能です。
余談
当社では current_stop_sequence を使うロジックを最優先で採用しています。
その理由としては GTFS リアルタイム以外の形式で配信されているデータの場合、current_stop_sequence に相当する情報が配信されていることが多いからです。
4. 遅れの時間を算出するとき
仕様
TripUpdate に含まれる StopTimeUpdate には バス停に対して何分に発or着するかという情報と、発or着の定刻に対して何分遅れているかという情報が入っています。
StopTimeUpdate の遅れ情報は配列で配信されています。
実際のデータ
そんな StopTimeUpdate ですが様々なパターンでデータが配信されています。
通過済みバス停は返却されない
系統の停車バス停全部
一部バス停に対しての情報が抜けている
気をつけること
配列で配信されているこのデータの個数は、上の画像の通りパターンによって異なります。
例えば終点への到着時刻は配信データの何個目なのか算出する場合、3個目の要素なのか・4個目の要素なのか・2個目の要素なのかと変わってきます。
このようにバス会社によって異なるため、データを確認し、どのパターンで扱えるかを調べておく必要があります。
また、ユーザーが一番欲しい情報は乗るバス停・降りるバス停に対して、あとどれくらいで着くのかということです。
そのためこれらのパターンを考慮しつつ、欠損がある際などは、必要に応じてリアルタイム配信データと GTFS の時刻表のデータとを連携し、時間を算出する必要があります。
最後に
今回一部ですが紹介させていただいたように、一言でGTFSリアルタイムといっても、比べてみると多くの違いがあったりします。
当社ではこのようにさまざまな特徴あるデータを考慮した上で、1つでも多くのバスロケーション情報をユーザーに提供できるように取り組んでいますので、是非アプリをご利用ください。