IoT機器のデータをお手軽にAWS IoTからS3に上げてAthenaで検索できるようにした設計判断の例

# TL;DR

お手軽にIoT機器（車載センサー）からデータを集めたい、
集めたデータをお手軽に閲覧したい、という目標を持って、
toteというプロダクト（車載センサーデータ収集基盤）を開発してきました。
cf. https://speakerdeck.com/yusuke_takagi_dn/bu-pin-falsesubetewoshou-falsezhong-ni-awswohuruhuo-yong-sitache-zai-sensadetashou-ji-ji-pan-falsekai-fa
その開発中に下した設計判断の例をご紹介します。

「AWS IoTからS3にHive形式でデータを格納してAthenaで効率よく検索する」ためのポイントについては、既に以下の記事に詳細にまとめられています。
cf. https://qiita.com/yoshiei_sato/items/cd9f559a94e01c889abe
なので、本記事ではそれ以外の種々の判断材料について記述します。

IoT機器からクラウドにデータを収集、利用しようとしている方々のご参考になれば幸いです。

もちろん要件や方針によっては私たちが下した設計判断をそのまま適用することはできないでしょう。
参考材料の一つとしてご覧いただけると嬉しいです。

# 前提

- IoT機器のデータをお手軽にAWSに上げて検索したい
    - IoT機器のデータをAWS IoT、S3に上げてAthenaで検索する
    - IoT機器（車載コンピューターとセンサー）をお手軽につなげたい
    - 集めたデータをお手軽に見られるようにしたい
    - 開発期間も短期なので重厚長大なものを作りたくない（必要性の不明な機能を増やしたくない）
- リアルタイム性はそれほど高くない
    - 私たちのユースケースでは、10ms周期でサンプリングするセンサーはありましたが、リアルタイムでクラウドに上げる/可視化する必要はありませんでした

# なぜAthena、S3を使うのか

AthenaはS3に置いたファイルに対してSQLクエリを発行してデータを検索することができます。

私たちのユースケースでは不定形なデータ検索をお手軽、アドホックに行いたいので、Athenaを使うことを選びました。
また、Athenaの検索対象としてIoT機器で作成したデータファイルをそのままアップロードしてS3に置くことにしました。

ビッグデータに対して定型処理を効率的、低コストに行うのであればEMR、Redshift、DynamoDBなど他のソリューションの方が適切かもしれません。

cf. https://aws.amazon.com/jp/blogs/news/top-10-performance-tuning-tips-for-amazon-athena/
私たちが今回取った設計判断は必ずしもAthenaのベストプラクティスに従ったものではありません。
その理由は大まかに言うとAthenaでの検索性能よりもお手軽さを優先したからです。
私たちのユースケースではそこまでの検索性能を必要とするものではありませんでした。

# データはjson式を複数行並べたログファイルとする

### csv、tsv、json、Parquet
Athenaではこれらのフォーマットのファイルを扱うことができます。
私たちはjsonを選びました。

jsonはcsv、tsvに比べて自己記述的でメタタグを含められます。
csv、tsvに比べてjsonのテキストサイズは大きくなりますが、後述のgzip圧縮すると圧縮後のファイルサイズはさほど変わりありませんでした。

ParquetはAthenaでの検索性能は良さそうですが、
IoT機器側で扱いにくい（複数データが集約されてしまう）と判断しました。
また、圧縮率はjsonをgzip圧縮した場合の方が優れていました。

### 1つのjson式に複数個のデータを詰め込まない

データを最小単位に分割したものを1行のjson式に入れ、
json式を複数行並べることを選びました。

例えばこんな感じです。

温度と湿度を同時に計測できるセンサーのデータファイル（温度ファイルと湿度ファイルに分割）
```{"timestamp": "aaaaa", "type": "temperature", "value": "xx.x"}
{"timestamp": "bbbbb", "type": "temperature", "value": "yy.y"}
{"timestamp": "ccccc", "type": "temperature", "value": "zz.z"}
```
```{"timestamp": "aaaaa", "type": "humidity", "value": "XX.X"}
{"timestamp": "bbbbb", "type": "humidity", "value": "YY.Y"}
{"timestamp": "ccccc", "type": "humidity", "value": "ZZ.Z"}
```

Parquetを選ばなかった理由とも被りますが、
複数個/複数行のIoTデータを1つのjson式にまとめようとすると、
IoTデータ単位でファイル出力することができなくなるからです。

こうすることにより、IoT機器（車載コンピューター）側ではデータファイルをテキスト形式で中間処理することが楽になりました。
Linuxの標準的なコマンドでテキスト処理をすることも可能になりました。

また、温度と湿度を分割し、jsonの形式を統一することにより、センサーの種類やデータ種別によらずAthenaで統一的なクエリ（`select timestamp, type, valule from data_table`のように）でデータ検索できるようになりました。

同時に計測された温度と湿度を横に並べて見たい時は以下のようなクエリを発行します。
```SELECT timestamp,
arbitrary(temperature)  AS temperature,
arbitrary(humidity)  AS humidity
FROM 
(
SELECT timestamp,
CASE WHEN type='temperature' THEN value END AS temperature,
CASE WHEN type='humidity' THEN value END AS humidity,
FROM data_table
) t
group by timestamp
ORDER BY  timestamp
limit 20
; 
```
すると以下のような結果が得られます。
```timestamp,  temperature,  humidity
aaaaa,  xx.x,  XX.X
bbbbb,  yy.y,  YY.Y
ccccc,  zz.z,  ZZ.Z
```

# データはアップロード前に圧縮する

Athenaはいくつかの圧縮形式をサポートしています。
cf. https://docs.aws.amazon.com/ja_jp/athena/latest/ug/compression-formats.html

私たちはIoT機器（車載コンピューター）内でデータをgzip圧縮し、圧縮データをアップロードすることを選びました。

### メリット
- ファイルサイズが小さくなる
- 通信量が減る
    - 有線やWiFi接続されたIoT機器ならばともかく、3G/4G SIM等でデータをアップロードする場合、通信料金の影響は大きい
- S3に置いてAthenaで検索する時のデータスキャン量が減る
cf. https://aws.amazon.com/jp/athena/pricing/

### デメリット
- 特に思いつかないけれど、圧縮ファイルをテキストエディタ等で見辛くなるところ？

# データアップロード

AWS IoTにデータをpublishする際のtopicの付け方にも工夫をしています。
詳細は以下の記事に書かれているので、本記事では触れません。
cf. https://qiita.com/yoshiei_sato/items/cd9f559a94e01c889abe

### fluentd

データファイルは単純なテキスト形式のログファイルなので、fluentdでAWS IoT、S3に上げるという選択肢もありそうですが、今回は検証しませんでした。

# アップロード後の変換

### AWS側でデータ受信時の変換

私たちのユースケースで必要なかったため、AWS側でデータ受信時の変換はしませんでした。

データ変換やデータマートへの格納が必要なケースでは、Kinesis Data StreamsやKinesis Data Firehoseなどの利用が適切かもしれません。

Athenaの検索性能を上げるためにjsonをParquetに変換することが必要なケースなども、このタイミングでAWS側でデータ変換すると良いでしょう。

### データマート

私たちのユースケースで必要なかったため、データマートへの格納はしませんでした。
（一部のユースケースではデータ収集基盤につながるアプリ側でMongoDBにデータを格納していました）