Carmenでジオコーダーを作る

この記事は [FOSS4G Advent Calendar 2019](https://qiita.com/advent-calendar/2019/foss4g) の25日目の記事です

# はじめに

[Carmen](https://github.com/mapbox/carmen)と[国土数値情報の行政区域データ](http://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N03-v2_3.html)を使ってジオコーダーを作りました。

# [Carmen](https://github.com/mapbox/carmen)とは

ベクタータイル（[MVT](https://docs.mapbox.com/vector-tiles/specification/)）ベースのジオコーダーです。Mapboxの[Geocoding API](https://docs.mapbox.com/help/how-mapbox-works/geocoding/)はこれを使って実装されています。

# サンプル

## Forward Geocoding

> 22時〜9時の間は停止します、また、時期をみて予告なく閉じます、ご了承ください

https://vt-cm01-stg.mapion.co.jp/geocoder/geocoding?access_token=mt-pk.eyJ1IjoibWFwaW9uIiwiYSI6IjlrMG4zaWNwNHFiMXAzOHloZ2djd3lvMm0ifQ.FUpciYWJ81QJkjAy7_AcoA&q=大磯町

### パラメータ

- access_token
  - 認証用。ここでは無視して構いません
- q
  - Forwad Geocodingしたい地名

### 出力結果（GeoJSON）

```json
{
  "type": "FeatureCollection",
  "query": [
    "大",
    "磯",
    "町"
  ],
  "features": [
    {
      "id": "data.771",
      "type": "Feature",
      "place_type": [
        "data"
      ],
      "relevance": 1,
      "properties": {
        "code": "14341"
      },
      "text": "神奈川県中郡大磯町",
      "place_name": "神奈川県中郡大磯町",
      "matching_text": "大磯町",
      "matching_place_name": "大磯町",
      "bbox": [
        139.25085050564633,
        35.29728800863472,
        139.33406953288272,
        35.33443858597201
      ],
      "center": [
        139.29246001926452,
        35.315863297303366
      ],
      "geometry": {
        "type": "Point",
        "coordinates": [
          139.29246001926452,
          35.315863297303366
        ]
      }
    }
  ]
}
```

## Reverse Geocoding

> 22時〜9時の間は停止します、また、時期をみて予告なく閉じます、ご了承ください

https://vt-cm01-stg.mapion.co.jp/geocoder/geocoding?access_token=mt-pk.eyJ1IjoibWFwaW9uIiwiYSI6IjlrMG4zaWNwNHFiMXAzOHloZ2djd3lvMm0ifQ.FUpciYWJ81QJkjAy7_AcoA&q=141.353611,43.0625

### パラメータ

- access_token
  - 認証用。ここでは無視して構いません
- q
  - Reverse Geocodingしたい経度,緯度

### 出力結果（GeoJSON）

```json
{
  "type": "FeatureCollection",
  "query": [
    141.353611,
    43.0625
  ],
  "features": [
    {
      "id": "data.143",
      "type": "Feature",
      "place_type": [
        "data"
      ],
      "relevance": 1,
      "properties": {
        "code": "01101"
      },
      "text": "北海道石狩振興局札幌市中央区",
      "place_name": "北海道石狩振興局札幌市中央区",
      "bbox": [
        141.20187360558248,
        42.997474721281435,
        141.3896355507402,
        43.0861158375759
      ],
      "center": [
        141.29575457816134,
        43.04179527942867
      ],
      "geometry": {
        "type": "Point",
        "coordinates": [
          141.29575457816134,
          43.04179527942867
        ]
      }
    }
  ]
}
```

> 当該都道府県が「北海道」の場合、該当する支庁・振興局の名称が入ります

# 図

![carmen.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56991/db44336d-f990-828c-5ad1-99130db96644.png)

# 手順

1. 国土数値情報の行政区域データ（GeoJSON）を最適化
2. tippecanoeでベクタータイル化
3. carmen-index.jsでインデックス化
4. これでジオコーダに必要なデータが作成される
  1. ***.fuzzy
  2. ***.grid.rocksdb
  3. ***.mbtiles
5. 後は[Carmen](https://github.com/mapbox/carmen)にクエリーを投げるだけ

> 手順4までが事前に準備しておくものですが、今回の場合、数分で完了しました。
また、ベクタータイル, インデックス共にz12までとしています。

# 補足

Carmenでgeocodingした結果をそのまま出力する仕様です。詳細は[ここ](https://github.com/mapbox/carmen/blob/master/docs/api.md#geocode)を参照してください（ソースコードへのリンク切れてますが...）。

# 余談

Rustで作り直す[プロジェクト](https://github.com/mapbox/carmen-core)が進んでいるようです。Mapboxのリポジトリを見渡してみるとRustを使ったものがちょっとずつ増えてきている気がします。GolangではないのはGoogle製だからでしょうか。