Elasticsearchの検索結果をベクトルタイルとしてNodejsで配信する


概要

個人的な興味で、ベクトルタイル活用の可能性を試してみたいと思い、Elasticsearchでの検索結果をMapboxのバイナリベクトルタイル形式にして配信するというよくわからないタイルサーバーをNodejsで作って、オープンソースプロジェクトとして公開してみました。作ったリポジトリは以下の通り。

  • elastic2mvt: z/x/yと検索クエリを受け取ってバイナリベクトルタイルを1枚だけ生成するモジュール
  • es_tileserv: NodejsのExpressで構築したElasticsearch用のベクトルタイル配信サーバー

こういう使い方がそもそも可能なのかも含めて、かなり試験的で、手探りでAPI仕様など考えていますので、今後ここで書いた以上に内容がガラッと変わる可能性がありますが、もし何かアイデアなどいただけたらと思い、ツールの紹介をします。

長くなりそうなので、ソースコードの説明はここではしませんので、ご興味のある方は各自ご覧ください。不明点があればリポジトリにIssueください。

使い方

DockerでElasticsearchも含めて、全て起動できるように設定しています。タイルサーバーのDockerイメージもDocker hubに上げていますので、最新のソースコードで実行する場合は以下のようにすれば、Elasticsearchと配信サーバーがpm2で立ち上がります。

git clone [email protected]:JinIgarashi/es_tileserv.git
cd es_tileserv
npm run docker:start

もしソースコードを修正したら、npm run docker:buildすれば最新のイメージをビルドします。

テストデータとしてケニアのナロックタウンの建物ポリゴンデータだけ用意しました。以下のコマンドでElasticsearchにインデックスを作ります。ogr2ogrを使いますので、GDALが入っていない場合はインストールをお願いします。

cd sample-data
./insert_test_data.sh

次のようにして、osm_building_narokというインデックスができていればOKです。

ogrinfo ES:http://localhost:9200

INFO: Open of `ES:http://localhost:9200'
      using driver `Elasticsearch' successful.
1: osm_building_narok (Multi Polygon)

APIの仕様について

サーバーを立ち上げたあと、http://localhost:8080/docsをブラウザで開くとSwaggerでAPIを試せます。

/api/tile/{z}/{x}/{y}.{ext}というAPIを使います。Try it outボタンを押して、デフォルトのExampleのままExecuteを押して、200が返れば成功しています。

実行結果

これだけだとよくわからないので、ブラウザで以下のURLを叩いてみます。

http://localhost:8080/api/tile/14/9824/8241.pbf?indices=%5B%7B%22name%22%3A%22osm_building_narok%22%2C%22geometry%22%3A%22geometry%22%2C%22query%22%3A%7B%22term%22%3A%7B%22building%22%3A%22school%22%7D%7D%7D%5D

8241.pbfがダウンロードされましたので、QGIS3.14以上のバージョンでドラッグ&ドロップしてみてみます。なんかポリゴンが表示されました!QGISのダウンロードはこちらから。

でももっと動的に画面動かしながらベクトルタイルを見たいということで、QGISのベクトルタイル機能でみてみます。

URLには次のものを指定してみます。学校だけではつまらないのでとりあえず、検索条件なしで設定します。

http://localhost:8080/api/tile/{z}/{x}/{y}.pbf?indices=[{"name":"osm_building_narok","geometry":"geometry"}]

こんな感じにして、OKを押します。

ブラウザパネルのVector Tilesに表示されました。

追加したベクトルタイルを表示する前に、ケニアのナロックタウンの場所をQGISで表示しておきましょう。ここではMaptiler PluginのBasicを追加してみます。アクセスキーは事前に取得お願いします。

ナロックタウンはナイロビの西側のこの辺です。

思いっきりズームしましょう。人口5万人程度の小さなマサイ族の街です。なんでこのナロックタウンをサンプルデータとして選んだかというと、自分が以前住んで仕事してたから。

さてここで、作成したベクトルタイルを地図に追加します。ブラウザパネルのVector Tileelastic MVT testをダブルクリックすれば良いです。

QGISにElasticsearchからのベクトルタイルがちゃんと表示されました!

ターミナルを見るとログがちゃんと出ていて動いているらしいことがわかります。

es_tileserv_1    | 06:18:20 2|es_tileserv  | GET /api/tile/13/4914/4121.pbf?indices=[%7B%22name%22:%22osm_building_narok%22,%22geometry%22:%22geometry%22%7D] 200 51.559 ms - 0
es_tileserv_1    | 06:18:20 1|es_tileserv  | GET /api/tile/13/4914/4122.pbf?indices=[%7B%22name%22:%22osm_building_narok%22,%22geometry%22:%22geometry%22%7D] 200 53.046 ms - 0

今後の展望

  • フロントエンドでMapboxGL JSを使って動的に検索ワードを変えつつ、ベクトルタイルを地図に表示したい。
  • もしできたら、es_tileservで検索して表示するMapbox GL JSのプラグインを作りたい。
  • Elasticsearchのいろんな検索に対応できるようにAPIの仕様を洗練させたい(自分はElasticsearchは素人同然なので検索ワードのAPIへの指定方法とかかなり手探りで作りました。)。

一昨日くらいから突貫で作ったので、いろいろと突っ込みどころがあるかと思いますが、もし何かAPI仕様について良い案や、こんな使い方もできるんではというアイデアなどありましたら、GithubのリポジトリにIssueください。

よろしくお願いします。