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

## 概要

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

- [elastic2mvt](https://github.com/JinIgarashi/elastic2mvt): z/x/yと検索クエリを受け取ってバイナリベクトルタイルを１枚だけ生成するモジュール
- [es_tileserv](https://github.com/JinIgarashi/es_tileserv): NodejsのExpressで構築したElasticsearch用のベクトルタイル配信サーバー

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

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

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

```
git clone git@github.com: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](http://localhost:8080/docs)をブラウザで開くとSwaggerでAPIを試せます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/858331/f1fee37a-0c9e-6fe4-ac40-892a5fc688e4.png)

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/858331/ef66b42b-8667-1f91-d57f-a795e4f147ea.png)

実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/858331/dc5c8f1f-5a47-5404-c81f-c7ec75b0c542.png)

これだけだとよくわからないので、ブラウザで以下の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のダウンロードは[こちら](https://qgis.org/ja/site/forusers/download.html)から。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/858331/e48bb560-62c5-066f-f0a2-f20f3de8f4a6.png)

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/858331/1fff6339-6a89-e40b-eb2f-51fad5c0fe90.png)

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

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

こんな感じにして、OKを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/858331/f45b13e1-ff3c-965a-8f42-f78273959fb1.png)

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/858331/bf26cea8-ebff-096f-9d66-b127068ba829.png)

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

ナロックタウンはナイロビの西側のこの辺です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/858331/5c9abc1c-5e4a-0754-d1af-61d5de9a2e3a.png)

思いっきりズームしましょう。人口５万人程度の小さなマサイ族の街です。なんでこのナロックタウンをサンプルデータとして選んだかというと、自分が以前住んで仕事してたから。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/858331/36550363-b1bc-623c-4cc0-1b3ec254b8bc.png)

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

QGISにElasticsearchからのベクトルタイルがちゃんと表示されました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/858331/8b292059-a6a4-a330-c6f1-4c62a3bb889f.png)

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

```log
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の[リポジトリ](https://github.com/JinIgarashi/es_tileserv)にIssueください。

よろしくお願いします。