OSRMのサーバを立ち上げてルート検索を行う

OpenStreetMapのデータをもとにルート検索を行える、OSSのルート検索エンジンの1つに、OSRM (Open Source Routing Machine, http://project-osrm.org/) がある。今回は、PC上にOSRMのサーバを用意して、ルート検索を行う。

環境

  • OS: Ubuntu 20.04 LTS (Windows 11 Home: 21H2のWSL2にインストール)
  • Docker Engine: 20.10.7 (上記のUbuntuにインストールしたCommunity Edition)
  • OSRM: 5.26.0

ルート検索の準備

OSRMのサーバをPC上に立てる。OSRMのサービスを構成する複数のソフトウェアがGithubで公開されているが、今回はそのなかからルート検索エンジンの本体にあたるosrm-backendを使う。osrm-backendのリポジトリのQuick StartにDockerコンテナを用いたサーバ構築手順が書かれており、その流れに沿って作業をする。

はじめにGeofabrikからOpenStreetMapのデータを取得する。Quick Startの手順ではベルリンのデータをダウンロードしているが、ここでは日本の関東地方のデータをダウンロードする。

$ wget https://download.geofabrik.de/asia/japan/kanto-latest.osm.pbf

次に、ダウンロードしたOpenStreetMapのデータを加工する。OSRMでは、ルート検索の計算プロセスとして「Contraction Hierarchies (CH)」と「Multi-Level Dijkstra (MLD)」の2種類が用意されている。どちらの計算プロセスを選択しても、ルート検索の処理速度を向上させるために事前にデータ加工を行う必要がある。Quick Startには、巨大な距離行列 (どの程度の大きさか具体的な指標は書かれていないが) を扱うような場合を除いて、基本的にMLDを使うのがおすすめと書かれている。Quick Startの手順もMLDを使ったものになっているので、ここでもMLDを使うことにする。

先ほどダウンロードしたOpenStreetMapのデータの置かれているディレクトリで、以下のMLD用のデータ加工のコマンドを実行する。

$ docker run -t -v "${PWD}:/data" osrm/osrm-backend osrm-extract -p /opt/car.lua /data/kanto-latest.osm.pbf
$ docker run -t -v "${PWD}:/data" osrm/osrm-backend osrm-partition /data/kanto-latest.osrm
$ docker run -t -v "${PWD}:/data" osrm/osrm-backend osrm-customize /data/kanto-latest.osrm

実行結果として、以下のファイルが生成される。

$ ls kanto-latest.osrm*

kanto-latest.osrm                   kanto-latest.osrm.enw                 kanto-latest.osrm.properties
kanto-latest.osrm.cell_metrics      kanto-latest.osrm.fileIndex           kanto-latest.osrm.ramIndex
kanto-latest.osrm.cells             kanto-latest.osrm.geometry            kanto-latest.osrm.restrictions
kanto-latest.osrm.cnbg              kanto-latest.osrm.icd                 kanto-latest.osrm.timestamp
kanto-latest.osrm.cnbg_to_ebg       kanto-latest.osrm.maneuver_overrides  kanto-latest.osrm.tld
kanto-latest.osrm.datasource_names  kanto-latest.osrm.mldgr               kanto-latest.osrm.tls
kanto-latest.osrm.ebg               kanto-latest.osrm.names               kanto-latest.osrm.turn_duration_penalties
kanto-latest.osrm.ebg_nodes         kanto-latest.osrm.nbg_nodes           kanto-latest.osrm.turn_penalties_index
kanto-latest.osrm.edges             kanto-latest.osrm.partition           kanto-latest.osrm.turn_weight_penalties

OSRMのサービスを5000番ポートで起動すれば、ルート検索を実行できるようになる。

$ docker run -t -i -p 5000:5000 -v "${PWD}:/data" osrm/osrm-backend osrm-routed --algorithm mld  /data/kanto-latest.osrm

ルート検索の実行

OSRMのサーバが用意できたので、ルート検索を試してみる。検索対象は、東京駅の八重洲口から羽田空港の第1ターミナルまでの道のりとする。

OSRMのサーバの使い方は、OSRMのAPIドキュメント(2022/07/28時点でドキュメントのバージョンはv5.24.0)に書かれている。OSRMのサーバは複数のサービスを提供しており、今回はそのなかから、2点間の最速ルートを探すRoute serviceを使う。APIドキュメントのRoute serviceの箇所を参照して、OSRMのサーバに送るリクエストを準備する。

Route serviceのリクエストは、出発地点と到着地点それぞれの緯度経度が必須のパラメータとなる。出発・到着地点の緯度経度の取得方法として、OpenStreetMapのWebサイトで提供されている地物検索の機能を使い、それぞれの地点付近の適当なノードを探すアプローチをとる。

出発地点の東京駅八重洲口は、ID: 6397151768のノードの緯度経度35.6798851, 139.7681482を設定する。

© OpenStreetMap contributors

到着地点となる羽田空港第1ターミナルは、ID: 2206530973のノードの緯度経度35.5491518, 139.7845835を設定する。

© OpenStreetMap contributors

また、ルート検索結果を地図上に可視化するときなどにデータの扱いが便利になるため、以下のオプションをリクエストに付与する。

  • 検索結果のルートのジオメトリをgeojson形式で取得するためのgeometries=geojson
  • 検索結果のルートのジオメトリを詳細な部分まで取得するためのoverview=full

出発・到着地点の緯度経度 (「経度,緯度」の順番にする必要がある点に注意) と追加のオプションを設定したリクエストを、自身のPC上で起動したOSRMサーバに送る。

$ curl "http://127.0.0.1:5000/route/v1/driving/139.7681482,35.6798851;139.7845835,35.5491518?geometries=geojson&overview=full" 

以下のようなレスポンスが返ってくれば、ルート検索が実行できている。

{"code":"Ok","routes":[{"geometry":{"coordinates":[[139.768429,35.679767],[139.768491,35.679864],[139.768635,35.68016],
...省略...
[139.784681,35.549197]],"type":"LineString"},"legs":[{"steps":[],"distance":21800,"duration":1230.7,"summary":"","weight":1230.7}],"distance":21800,"duration":1230.7,"weight_name":"routability","weight":1230.7}],"waypoints":[{"hint":"SwJCgP___3-0AAAA0gAAAAAAAABVAAAAL4OWQkw1QkEAAAAAQ1YNQrQAAADSAAAAAAAAAFUAAADvAwAAbbJUCBduIAJUsVQIjW4gAgAAvwHZCL3c","distance":28.611262,"name":"","location":[139.768429,35.679767]},{"hint":"bjgzgP___38RAAAARgAAAAAAAAAAAAAAigmZQbnlaUIAAAAAAAAAABEAAABGAAAAAAAAAAAAAADvAwAA6fFUCA1wHgKI8VQI4G8eAgAArxTZCL3c","distance":10.116086,"name":"","location":[139.784681,35.549197]}]}