🚉

JR東日本のリアルタイムデータで乗換案内(OTP)を動かす -2.REST API 編-

2024/10/18に公開

本記事では、JR東日本のリアルタイムデータを用いてOpenTripPlanner2 (OTP2) を動作させ、乗換案内を提供する方法について解説します。今回は、OTP2のREST APIに焦点を当て、リアルタイム情報がどのように取得できるのか、そしてAPIレスポンスからどのような情報を読み取れるのかを詳しく見ていきます。

なお、この記事は前回の記事、JR東日本のリアルタイムデータで乗換案内(OTP)を動かす -1.Docker起動編-で動かしたOpenTripPlannerのレスポンスを眺めていきます。OpenTripPlannerのバージョンの違いなどによりAPIレスポンス形式は変わるので、この記事と同じレスポンス形式を利用したい場合には、OpenTripPlannerのコンテナイメージはopentripplanner/opentripplanner:2.6.0_2024-07-11T01-17に合わせてください。

https://zenn.dev/takoyaki3/articles/25c036daaf0d75

https://github.com/takoyaki-3/odpt-challenge2024-jre-otp-docker

リアルタイム情報とは?

リアルタイム情報とは、刻々と変化する状況を反映した最新の情報のことです。乗換案内においては、列車の遅延や運休情報などがリアルタイム情報に該当します。OTP2は、リアルタイム情報を利用することで、より正確で現実的な乗換案内を提供することができます。

OTP2 REST API

OTP2は、REST APIを通じて様々な機能を提供しています。本記事では、下記のAPIについて解説します。

  • 駅一覧取得API
  • 路線一覧取得API
  • 経路検索API
  • 駅時刻表取得API
  • 列車ごとの時刻表取得API

駅一覧取得API

駅一覧を取得するAPIは、OTP2が認識している駅の一覧を取得するために使用します。

http://localhost:8080/otp/routers/default/index/stops/

APIレスポンスは、駅ID、駅名、縦度緯度を含むJSON配列形式で返されます。

[{"id":"1:4010","name":"崖根","lat":35.41478,"lon":139.9338},{"id":"1:2909","name":"厚木","lat":35.44382,"lon":139.3786},{"id":"1:2918","name":"橋本","lat":35.59484,"lon":139.3451}, ...]

路線一覧取得API

路線一覧を取得するAPIは、OTP2が認識している路線の一覧を取得するために使用します。

http://localhost:8080/otp/routers/default/index/routes/

APIレスポンスは、路線ID、路線名、運行モード、路線カラー、運行会社名を含むJSON配列形式で返されます。

[{"id":"1:41","longName":"宇都宮線","mode":"RAIL","color":"FF9845","agencyName":"JR東日本"}, ...]

レスポンスには色情報も含まれているので、次のように各路線ごとのラインカラーも取得できます。

経路検索API

経路検索APIは、指定された出発地と目的地間の経路を検索するために使用します。

http://localhost:8080/otp/routers/default/plan

APIリクエストには、以下のようなパラメータを指定します。

  • fromPlace: 出発地の縦度緯度
  • toPlace: 目的地の縦度緯度
  • mode: 利用する移動手段 (例: TRANSIT,WALK)
  • date: 探索する日付
  • time: 探索する時刻
  • maxWalkDistance: 最大歩行距離 (メートル)
  • arriveBy: 出発時刻指定か到着時刻指定か (falseが出発時刻指定)
  • numItineraries: 提案する経路の数
  • useRealtime: リアルタイム情報を使用する (trueでリアルタイム情報を使用)

APIレスポンスは、検索された経路を含むJSON形式で返されます。経路情報は、planオブジェクト内のitineraries配列に格納されています。各経路は、複数のlegs(移動区間)から構成されます。

今回は下の図のように、両国駅付近から北朝霞駅付近までの経路検索を行ってみました。

経路検索をすると、planitinerariesに経路が格納され、各径路における歩行や1つの列車がlegsという要素に格納されていきます。今回の例におけるLegの考え方は下の図のようになります。

以下が実際のJSON形式でOpenTripPlannerから返却されるレスポンスです。

{
    "requestParameters": {
        "mode": "TRANSIT,WALK",
        "date": "2024-10-06",
        "arriveBy": "false",
        "fromPlace": "35.695887,139.794845",
        "useRealtime": "true",
        "toPlace": "35.818161,139.590911",
        "time": "18:40pm",
        "maxWalkDistance": "1000",
        "numItineraries": "3"
    },
    "plan": {
        "date": 1728207110122,
        "from": {
            "name": "Origin",
            "lon": 139.794845,
            "lat": 35.695887,
            "vertexType": "NORMAL"
        },
        "to": {
            "name": "Destination",
            "lon": 139.590911,
            "lat": 35.818161,
            "vertexType": "NORMAL"
        },
        "itineraries": [
            {
                "duration": 4649,
                "startTime": 1728207357000,
                "endTime": 1728212006000,
                "walkTime": 1156,
                "transitTime": 2880,
                "waitingTime": 613,
                "walkDistance": 1242.18,
                "walkLimitExceeded": false,
                "generalizedCost": 7460,
                "elevationLost": 0.0,
                "elevationGained": 0.0,
                "transfers": 2,
                "fare": {
                    "fare": {},
                    "details": {}
                },
                "legs": [
                    {
                        "startTime": 1728207357000,
                        "endTime": 1728207780000,
                        "departureDelay": 0,
                        "arrivalDelay": 0,
                        "realTime": false,
                        "distance": 467.94,
                        "generalizedCost": 800,
                        "pathway": false,
                        "mode": "WALK",
                        "transitLeg": false,
                        "route": "",
                        "agencyTimeZoneOffset": 32400000,
                        "interlineWithPreviousLeg": false,
                        "from": {
                            "name": "Origin",
                            "lon": 139.794845,
                            "lat": 35.695887,
                            "departure": 1728207357000,
                            "vertexType": "NORMAL"
                        },
                        "to": {
                            "name": "Ryogoku",
                            "stopId": "1:1219",
                            "stopCode": "JB21",
                            "lon": 139.79335,
                            "lat": 35.69576,
                            "arrival": 1728207780000,
                            "departure": 1728207780000,
                            "zoneId": "1219",
                            "vertexType": "TRANSIT"
                        },
                        "legGeometry": {
                            "points": "e|zxEguftYc@pBIr@?TLnAOrBAxA?\\L@?Jl@DL?B@@DCp@?HH?j@CDA@QBe@B{@FuB@c@SA",
                            "length": 25
                        },
                        "steps": [
                            {
                                "distance": 55.02,
                                "relativeDirection": "DEPART",
                                "streetName": "open area",
                                "absoluteDirection": "WEST",
                                "stayOn": false,
                                "area": true,
                                "bogusName": false,
                                "lon": 139.7949273,
                                "lat": 35.6961996,
                                "elevation": "",
                                "walkingBike": false
                            },
                            "..."
                        ],
                        "rentedBike": false,
                        "walkingBike": false,
                        "duration": 423.0
                    },
                    "..."
                ],
                "tooSloped": false,
                "arrivedAtDestinationWithRentedBicycle": false
            },
            "..."
        ]
    },
    "metadata": {
        "searchWindowUsed": 3600,
        "nextDateTime": 1728208260000,
        "prevDateTime": 1728203510000
    },
    "previousPageCursor": "MXxQUkVWSU9VU19QQUdFfDIwMjQtMTAtMDZUMDg6NTE6NTBafHw0MG18U1RSRUVUX0FORF9BUlJJVkFMX1RJTUV8ZmFsc2V8MjAyNC0xMC0wNlQwOTo1MDo1N1p8MjAyNC0xMC0wNlQxMTowMzoyNlp8NHw4MzE0fA==",
    "nextPageCursor": "MXxORVhUX1BBR0V8MjAyNC0xMC0wNlQwOTozMzo1N1p8fDQwbXxTVFJFRVRfQU5EX0FSUklWQUxfVElNRXxmYWxzZXwyMDI0LTEwLTA2VDA5OjUwOjU3WnwyMDI0LTEwLTA2VDExOjAzOjI2Wnw0fDgzMTR8",
    "debugOutput": {
        "precalculationTime": 32202,
        "directStreetRouterTime": 13031384,
        "transitRouterTime": 113141254,
        "filteringTime": 2002890,
        "renderingTime": 938542,
        "totalTime": 129165072,
        "transitRouterTimes": {
            "tripPatternFilterTime": 16407633,
            "accessEgressTime": 48694675,
            "raptorSearchTime": 41830269,
            "itineraryCreationTime": 6153575
        }
    },
    "elevationMetadata": {
        "ellipsoidToGeoidDifference": 37.62610415749396,
        "geoidElevation": false
    }
}

リアルタイム情報の確認

経路検索APIのレスポンスには、リアルタイム情報が含まれています。legs配列内の各オブジェクトは、以下のようなリアルタイム情報を含みます。

  • realTime: リアルタイム情報が利用可能かどうかを示すブール値
  • departureDelay: 出発時刻の遅延 (秒)
  • arrivalDelay: 到着時刻の遅延 (秒)
  • realtimeState: リアルタイム情報の状態 (例: SCHEDULED, UPDATED)

例えば、下記のlegオブジェクトは、リアルタイム情報が利用可能 ("realTime": true)で、出発時刻が420秒遅延している ("departureDelay": 420)ことを示しています。

{
  "startTime": 1728154340000,
  "endTime": 1728154640000,
  "departureDelay": 420,
  "arrivalDelay": 420,
  "realTime": true,
  "distance": 1734.25,
  "generalizedCost": 1065,
  ...
}

駅時刻表取得API

駅時刻表取得APIは、特定の駅の時刻表を取得するために使用します。

http://localhost:8080/otp/routers/default/index/stops/{stopId}/stoptimes

APIリクエストには、以下のようなパラメータを指定します。

  • stopId: 駅ID
  • timeRange: 取得する時刻の範囲 (秒)
  • numberOfDepartures: 取得する出発情報の数

APIレスポンスは、指定された駅の時刻表を含むJSON配列形式で返されます。時刻表情報は、patternオブジェクトとtimes配列から構成されます。patternオブジェクトは、運行パターンに関する情報を含み、times配列は、各列車の到着・出発時刻、遅延情報などを含みます。

リアルタイム情報の確認

駅時刻表APIのレスポンスにも、リアルタイム情報が含まれています。times配列内の各オブジェクトは、以下のようなリアルタイム情報を含みます。

  • realtime: リアルタイム情報が利用可能かどうかを示すブール値
  • realtimeState: リアルタイム情報の状態 (例: SCHEDULED, UPDATED)
  • arrivalDelay: 到着時刻の遅延 (秒)
  • departureDelay: 出発時刻の遅延 (秒)

例えば、下記のtimesオブジェクトは、リアルタイム情報が利用可能 ("realtime": true)で、到着時刻と出発時刻がそれぞれ180秒遅延している ("arrivalDelay": 180, "departureDelay": 180)ことを示しています。

{
  "stopId": "1:2233",
  "stopIndex": 32,
  "stopCount": 47,
  "scheduledArrival": 66900,
  "scheduledDeparture": 66900,
  "realtimeArrival": 67080,
  "realtimeDeparture": 67080,
  "arrivalDelay": 180,
  "departureDelay": 180,
  "timepoint": true,
  "realtime": true,
  "realtimeState": "UPDATED",
  "serviceDay": 1728140400,
  "tripId": "1:2221711B",
  "headsign": "大船"
}

このようにリアルタイムな駅の発車時刻と遅れが取れることで、次のような発車標に近いものを作ることができます。

なお、この発車標のサンプルコードは以下で公開しております。

https://github.com/takoyaki-3/odpt-challenge2024-jre-otp-docker/tree/main/sample/departure-board

列車ごとの時刻表取得API

列車ごとの時刻表取得APIは、特定の列車の時刻表を取得するために使用します。

http://localhost:8080/otp/routers/default/index/trips/{tripId}/stoptimes

APIリクエストには、列車ID (tripId)を指定します。

APIレスポンスは、指定された列車の時刻表を含むJSON配列形式で返されます。時刻表情報は、stopIdstopIndexscheduledArrivalscheduledDeparturerealtimeArrivalrealtimeDeparturearrivalDelaydepartureDelayなどを含みます。

リアルタイム情報の確認

列車ごとの時刻表APIのレスポンスにも、リアルタイム情報が含まれています。各オブジェクトは、以下のようなリアルタイム情報を含みます。

  • realtime: リアルタイム情報が利用可能かどうかを示すブール値
  • realtimeState: リアルタイム情報の状態 (例: SCHEDULED, UPDATED)
  • arrivalDelay: 到着時刻の遅延 (秒)
  • departureDelay: 出発時刻の遅延 (秒)

例えば、下記のオブジェクトは、リアルタイム情報が利用可能 ("realtime": true)で、到着時刻が-101秒、出発時刻が47秒遅延している ("arrivalDelay": -101, "departureDelay": 47)ことを示しています。

{
  "stopId": "1:2201",
  "stopIndex": 0,
  "stopCount": 42,
  "scheduledArrival": 64140,
  "scheduledDeparture": 64140,
  "realtimeArrival": 64039,
  "realtimeDeparture": 64187,
  "arrivalDelay": -101,
  "departureDelay": 47,
  "timepoint": true,
  "realtime": true,
  "realtimeState": "UPDATED",
  "serviceDay": -1,
  "tripId": "1:2221717A",
  "headsign": "碭子"
}

まとめ

OTP2のREST APIを利用することで、JR東日本のリアルタイムデータを取得し、遅延情報などを含む詳細な乗換案内を提供することができます。APIレスポンスからリアルタイム情報を読み取ることで、ユーザーに最新の情報に基づいた経路案内を提供することが可能となります。なお、本記事ではJR東日本のリアルタイムデータを利用する例を紹介しましたが、OTP2は他のデータソースにも対応しています。

今回はOpenTripPlannerのレスポンス形式を中心に見ていきましたが、気が向いたら「JR東日本のリアルタイムデータで乗換案内(OTP)を動かす -3.経路検索結果を眺める編-」として、経路検索された結果を具体的により詳しく見ていきたいと思います。

Discussion