TILE38紹介（1） ：基本コマンド


|TILE38紹介|
|:---|
|[TILE38紹介（1） ：基本コマンド](https://qiita.com/tesujiro/items/69f8970bd69d501cb0c8)|
|[TILE38紹介（2） ：空間系コマンド](https://qiita.com/tesujiro/items/0a998f2c6e3dd49d7429)|
|[TILE38紹介（3） ：Goプログラムからのアクセス1](https://qiita.com/tesujiro/items/fa7dfc079a94824cc77e)|
|[TILE38紹介（4） ：Goプログラムからのアクセス2](https://qiita.com/tesujiro/items/d9bf26233ce96bc3596f)|
|[TILE38紹介（5） ：Geofencing](https://qiita.com/tesujiro/items/e4b5a3df174e69516553)|

# TL;DR
- TILE38という地図情報データベースについて勉強したことをメモする。
- 色々な機能を持っているが、まずはCLIを使用して基本的なコマンドを説明する。
- 今後はGeoFencingやRedisクライアントからのAPI呼び出し、ベンチマーク（応答時間、メモリ使用量）なども記載して行きたい。
- 説明のための画像はOepnStreetMapデータを使用するJavascriptライブラリLeafletを使用して作成する。

# TILE38とは
- 地図情報に特化した機能を持つデータベース。
- メモリ上にデータを格納するので高速である。
- SQLではなく独自のコマンドを提供している。
- Geofencingという地図検索結果のHTTPコールバック機能を持つためリアルタイム性の高い処理が比較的容易に実現できる。
- シングルサーバ構成。（今のところは）クラスタ機能なし。
- CLI以外にRedisのプロトコルを実装しているので各種RedisClientからアクセス可能。
- Goで実装されている。
- データ表現はGeoJsonに対応。
- データベース検索時にLuaベースのスクリプトで条件を記述することが可能。
- 関連ページ：
[TILE38](https://tile38.com/)、[Github](https://github.com/tidwall/tile38)、[各種ドキュメント](https://tile38.com/documentation/)、[インストール](https://tile38.com/topics/getting-started/)

# 基本コマンド

| コマンド | どんな機能 |
|---------|---------------|
| SET | データ登録 |
| GET | データ取得 |
| SCAN | データ検索 |
| NEARBY | 点からの距離によるデータの検索 |

# サーバ起動
- 最初にtile38-serverでサーバを起動する。

```bash:
> tile38-server
tile38-server

   _______ _______
  |       |       |
  |____   |   _   |   Tile38 1.14.4 64 bit (amd64/darwin)
  |       |       |   Port: 9851, PID: 33700
  |____   |   _   | 
  |       |       |   tile38.com
  |_______|_______| 

2019/01/23 10:27:13 [INFO] Server started, Tile38 version 1.14.4, git 0000000
2019/01/23 10:27:14 [INFO] AOF loaded 202385 commands: 0.87s, 232031/s, 44 MB/s
```
- デフォルトで9851ポートが使用される。
- tile38-serverは終了するまで返ってこないので複数のターミナルを開きたくなければ"＆"付きでも構わない。（実行中に標準出力/標準エラー出力に何か情報が出力されることもない。）

# データ登録と取得
- tile38-cliを使用して緯度と経度を持つ点(now)を登録し表示する。
- Keyとidという概念があり、Keyはオブジェクトの集合の名前、idはKey内でのオブジェクト識別子を表す。

```bash:
> tile38-cli
127.0.0.1:9851> SET location now POINT 35.6581 139.6975
{"ok":true,"elapsed":"2.969468ms"}
127.0.0.1:9851> GET location now
{"ok":true,"object":{"type":"Point","coordinates":[139.6975,35.6581]},"elapsed":"22.735µs"}
```
- SETコマンドはSQLのINSERT,UPDATEの両方を兼ねる。
- パラメータ(NX,XX)追加によってINSERT,UPDATEとして使用することも可能。
- GETコマンドの結果はGeoJSON形式で返される。
- GeoJSONの座標(coordinates)の配列では緯度と経度が逆転していることに注意。
<img width="602" alt="Screen Shot 2019-01-24 at 16.27.04.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/41075/51ef1b43-2ec9-2f16-5cf8-fd92322a80db.jpeg">

# データ検索（SCAN,NEARBY）
- 複数個登録したデータから条件に合ったものを取得する。
- 以下の例では３件のオブジェクトを登録し、オブジェクト識別子にパターンマッチを適用する。

```bash:
127.0.0.1:9851> SET lunch ramen:A POINT 35.6586 139.6982
{"ok":true,"elapsed":"13.216µs"}
127.0.0.1:9851> SET lunch gyudon:B POINT 35.6570 139.6967
{"ok":true,"elapsed":"18.382µs"}
127.0.0.1:9851> SET lunch ramen:C POINT 35.6576 139.6948
{"ok":true,"elapsed":"12.791µs"}
127.0.0.1:9851> SCAN lunch MATCH ramen* IDS
{"ok":true,"ids":["ramen:A","ramen:C"],"count":2,"cursor":0,"elapsed":"1.029331ms"}
```

- ランチ場所の候補として、ラーメン屋２件と牛丼屋１件を登録した。
- idがラーメン屋に一致するものを対象にしてSCAN検索し、ラーメン屋２件のデータが取得できた。(MATCH ramen*)
- 取得する結果データの種類としてはIDのみを対象にした。(IDS)
- SCANコマンドとしてはidのパターンマッチ以外に各フィールの値や範囲の指定、Luaスクリプトによる複雑な条件指定も可能である。
<img width="602" alt="Screen Shot 2019-01-24 at 15.15.36.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/41075/1c3eb3ce-f672-1a25-845c-adf859ed02ce.jpeg">

- 次に同じデータを使用して、地理的に近いところを検索するためにはNEARBYコマンドを使用する。

```bash:
127.0.0.1:9851> NEARBY lunch POINT 35.6581 139.6975 100
{"ok":true,"objects":[{"id":"ramen:A","object":{"type":"Point","coordinates":[139.6982,35.6586]}}],"count":1,"cursor":0,"elapsed":"29.805µs"}
```
- 現在地から半径100メートルの条件で検索したところ、ラーメン屋Aのみがヒットした。

<img width="602" alt="Screen Shot 2019-01-24 at 16.11.13.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/41075/01f4d417-af69-b4d1-2121-b83171229e95.jpeg">