MapR Data Access Gatewayを使ってみる


本記事ではMapRのMEP(MapR Expansion Pack) 5.0からリリースされた **MapR Data Access Gateway** について紹介します。
Data Access Gatewayを利用することで、MapR-DB JSONに対してREST APIからアクセス可能となります。
MEP 5.0はMapR 6.0.1から利用可能となります。

本記事は[この辺の記事](https://maprdocs.mapr.com/home/MapROverview/MapRDataAccessGateway.html)をさらっと和訳した形になりますので、英語無問題の方はそちらからどうぞ！


# 概要

Data Access GatewayはクライアントとMapRクラスタ間のプロキシやゲートウェイとして振る舞います。
Data Access Gatewayが提供するREST-APIを使うことで、MapR-DB JSONのテーブル作成、削除、テーブルの更新や検索クエリを実行することが出来ます。

REST-APIには以下の特徴があります。

* オペレーションはステートレス
* オペレーションは同期実行
* リクエストの結果はバッファされない
* セキュアなMapRクラスタにアクセスする際にはWebコネクションはセキュア
* 以下の認証方法をサポート
    * ベーシック認証
    * JSON Web Tokens（JWT)を使ったトークンベース認証
* ユーザのインパーソネーションのサポート。すべてのデータアクセスは認証されたユーザとして実行される
* エラーの発生時にはレスポンスメッセージのbodyにHTTPエラーコードと詳細が返信される

また、Data Access Gatewayは1ノード単位で設定されるサービスとなりますので、本番サービスではHAとロードバランスを考慮して2台以上で設定されるべきです。
ただし、2018年8月現在ではMapR側でロードバランサは提供されていませんので、ユーザ側で用意する必要があります。

# Hands-On

とりあえず使ってみましょう、ということで以下はノンセキュアなMapRクラスタに対する作業記録になります。
APIの仕様から見たい人は[この辺](https://maprdocs.mapr.com/home/MapR-DB/JSON_DB/GettingStartedMapRDBJSONRESTAPI.html)や[この辺](https://maprdocs.mapr.com/home/MapR-DB/JSON_DB/MapRDBRESTAPI.html
)からどんどん行きましょう！（やってる内容は同じです）


```

まずはインスコ
[root@sample ~]# yum install  mapr-data-access-gateway -y
[root@sample ~]# /opt/mapr/server/configure.sh -R
[root@sample ~]# service mapr-warden restart

ポートから起動確認
[root@sample ~]# lsof -i:8243
COMMAND  PID USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
java    9538 mapr   85u  IPv6 30713650      0t0  TCP *:synapse-nhttps (LISTEN)
```

以下、MapR-FSのパス`/user/user01/db/dag_test`にテーブルを作成し、種々の作業をしていきます。
今回の作業は`curl`コマンドで行います。
また、テーブルへのパス中の'/'はAPIのコマンドとの違いをはっきりさせるために'%2F'を使いますが、'/'をそのまま使っても問題ありません。

```

user01ユーザ(パスワードがxxxx)でテーブル作成
[user01@sample ~]$ mkdir /mapr/sample/user/user01/db
[user01@sample ~]$ curl -X PUT 'https://sample:8243/api/v2/table/%2Fuser%2Fuser01%2Fdb%2Fdag_test' -u user01:xxxx -k

データ挿入
[user01@sample ~]$ curl -X POST 'https://sample:8243/api/v2/table/%2Fuser%2Fuser01%2Fdb%2Fdag_test' -u user01:xxxx -k \
>  -H 'Content-Type: application/json' \
>   -d '[{"_id":"user001","first_name":"John","last_name":"Doe"},
>  {"_id":"user002","first_name":"Jane","last_name":"Doe"},
>  {"_id":"user003","first_name":"Simon","last_name":"Davis"}]'

テーブル参照
[user01@sample ~]$ curl -X GET 'https://sample:8243/api/v2/table/%2Fuser%2Fuser01%2Fdb%2Fdag_test' -u user01:xxxx -k
{
"DocumentStream":[
{"_id":"user001","first_name":"John","last_name":"Doe"},
{"_id":"user002","first_name":"Jane","last_name":"Doe"},
{"_id":"user003","first_name":"Simon","last_name":"Davis"}
]
}

first_nameフィールドのみ参照
[user01@sample ~]$ curl -X GET 'https://sample:8243/api/v2/table/%2Fuser%2Fuser01%2Fdb%2F/dag_test?fields=first_name' -u user01:xxxx -k
{
"DocumentStream":[
{"first_name":"John"},
{"first_name":"Jane"},
{"first_name":"Simon"}
]
}

last_nameで条件付き検索
[user01@sample ~]$ curl -g -X GET 'https://sample:8243/api/v2/table/%2Fuser%2Fuser01%2Fdb%2F/dag_test?condition={"$eq":{"last_name":"Doe"}}' -u user01:xxxx -k
{
"DocumentStream":[
{"_id":"user001","first_name":"John","last_name":"Doe"},
{"_id":"user002","first_name":"Jane","last_name":"Doe"}
]
}


条件付き検索＋参照フィールド限定
[user01@sample ~]$ curl -g -X GET 'https://sample:8243/api/v2/table/%2Fuser%2Fuser01%2Fdb%2F/dag_test?condition={"$eq":{"last_name":"Doe"}}&fields=_id,first_name' -u user01:xxxx -k
{
"DocumentStream":[
{"_id":"user001","first_name":"John"},
{"_id":"user002","first_name":"Jane"}
]
}

クエリプラン付きでクエリ実行
[user01@sample ~]$ curl -g -X GET 'https://sample:8243/api/v2/table/%2Fuser%2Fuser01%2Fdb%2F/dag_test?condition={"$eq":{"last_name":"Doe"}}&fields=_id,first_nae&getPlan=true' -u user01:xxxx -k
{
"DocumentStream":[
{"_id":"user001","first_name":"John"},
{"_id":"user002","first_name":"Jane"}
],
"QueryPlan":[[{"streamName":"DBDocumentStream","parameters":{"queryConditionPath":true,"projectionPath":["_id","first_name"],"primaryTable":"/user/user01/db/dag_test"}}]]
}

パスで`id`を指定してドキュメント更新
[user01@sample ~]$ curl  -X POST 'https://sample:8243/api/v2/table/%2Fuser%2Fuser01%2Fdb%2Fdag_test/document/user001'  -u user01:xxxx -k   -H 'Content-Type: application/json'   -d '{"$set":{"first_name":"Jay"}}'

パスで行(_id)を指定して更新の確認
[user01@sample ~]$ curl -X GET 'https://sample:8243/api/v2/table/%2Fuser%2Fuser01%2Fdb%2F/dag_test/document/user001' -u user01:xxxx -k
{"_id":"user001","first_name":"Jay","last_name":"Doe"}

idとカラムを指定してデータの上書き（その他のカラムは削除）
[user01@sample ~]$ curl  -X PUT 'https://sample:8243/api/v2/table/%2Fuser%2Fuser01%2Fdb%2Fdag_test/document/user001'  -u user01:xxxx -k   -H 'Content-Type: application/json'   -d '{"_id":"user001","nick_name":"Jon"}'

更新確認
[user01@sample ~]$ curl -X GET 'https://sample:8243/api/v2/table/%2Fuser%2Fuser01%2Fdb%2Fdag_test/document/user001' -u user01:xxxx -k
{"_id":"user001","nick_name":"Jon"}

カラムを増やして更新
[user01@sample ~]$ curl  -X POST 'https://sample:8243/api/v2/table/%2Fuser%2Fuser01%2Fdb%2Fdag_test/document/user001'  -u user01:xxxx -k   -H 'Content-Type: application/json'   -d '{"_id":"user001","first_name":"Jonathan","middle_name":"Michael"}'

更新確認
[user01@sample ~]$ curl -X GET 'https://sample:8243/api/v2/table/%2Fuser%2Fuser01%2Fdb%2Fdag_test/document/user001' -u user01:xxxx -k
{"_id":"user001","first_name":"Jonathan","middle_name":"Michael","nick_name":"Jon"}

行の削除
[user01@sample ~]$ curl -X DELETE 'https://sample:8243/api/v2/table/%2Fuser%2Fuser01%2Fdb%2F/dag_test/document/user001' -u user01:xxxx -k

削除確認
[user01@sample ~]$ curl -X GET 'https://sample:8243/api/v2/table/%2Fuser%2Fuser01%2Fdb%2F/dag_test' -u user01:xxxx -k
{
"DocumentStream":[
{"_id":"user002","first_name":"Jane","last_name":"Doe"},
{"_id":"user003","first_name":"Simon","last_name":"Davis"}
]

テーブル削除
[user01@sample ~]$ curl -X DELETE 'https://sample:8243/api/v2/table/%2Fuser%2Fuser01%2Fdb%2F/dag_test' -u user01:xxxx -k

[user01@sample ~]$ ls /mapr/sample/user/user01/db/
<表示なし>

```

問題なく動きましたね！

# 設定

Data Access Gatewayでは以下の2つのファイルで設定を行います

* `/opt/mapr/data-access-gateway/conf/properties.cfg`
* `/opt/mapr/data-access-gateway/conf/warden.data-access-gateway.conf`

`properties.cfg`での設定項目は以下となります

| パラメタ | デフォルト値 | 説明 |
|:--|--:|:--|
| th.token.expiration | 1800 | 認証トークンのexpire時間(秒) |
| rest.https.port | 8243 | HTTPSアクセス時のポート |
| rest.result.limit | 5000 | APIで返却されるドキュメントの上限数 |

`warden.data-access-gateway.conf`ではヒープサイズの設定を行います。

| パラメタ | デフォルト値 | 説明 |
|:--|--:|:--|
| service.heapsize.max | 3000 | ヒープの最大値(MB) |
| service.heapsize.min | 3000 | ヒープの最小値(MB) |



`warden.data-access-gateway.conf`を編集したら`# /opt/mapr/server/configure.sh -R`を実行して、`/opt/mapr/conf/conf.d/warden.daata-access-gateway.conf`にコピーされるか確認しましょう。
Wardenは`/opt/mapr/data-access-gateway/conf`以下ではなく、`/opt/mapr/conf/conf.d`以下のファイルを参照します!
反映されたら再起動をかけて終了です。

# おわりに

本記事は以上となります。
Data Access Gatewayを使うことでIoTデバイスからのデータ収集も簡単になりそうですね！
今後どのようなデータがたまっていくのか楽しみです。