要約
AWS IoTで受信したデータをS3にHive形式として保存すると、AthenaでのPartitionの作成が容易で検索性能向上や費用の削減に効果的。IoTデバイス側で最初からHive形式でトピックを指定しておけばS3へのHive形式での格納が容易。
目的
- 複数デバイス、複数センサから収集したデータをAthenaで検索したい。
- データ量が多くなることが想定されるので、検索性能を上げつつつも費用を抑えたい。もちろん検索クエリが簡易であることも重要。
- データを吸い出してから検索するまでの仕組みを簡素化してMVPを素早く実現したい。
構成
- IoTデバイス: IoTデバイスは複数あり、各デバイスに搭載された各種センサのデータを収集することを想定する。データのアップロードはAWS IoT Device SDKを用いてAWS IoT CoreのエンドポイントへPublishする。ここで指定するトピックをHive形式にすることでそのままS3へのデータ格納する。
- AWS IoT Core: IoTデバイスから受信したデータをルールエンジンで指定するキーに基づいてAmazon S3に格納する。受信したトピックを処理するためのルールクエリステートメントとアクションを設定することで、S3にHive形式で格納する。
- Amazon S3: データの格納先。
- Amazon Athena: Amazon S3に格納されたデータに対する検索エンジン。指定デバイスの任意のセンサに対して、時間範囲を指定してデータを取得するユースケースを想定する。
S3にHive形式で格納する
S3にHive形式で格納することで、容易にAthenaでパーティション分割することができる。パーティション分割により、スキャン対象データの母数を限定することができるため、selectの応答時間や料金を削減することができる。
参考:
https://qiita.com/qiita-kurara/items/4872d2eed6b7d0b73fd4
https://docs.aws.amazon.com/ja_jp/athena/latest/ug/partitions.html
S3にHive形式で格納するトピックとAWS IoTの設定
IoTデバイスでPublishするトピック
以下の様なHive形式のトピックにする。
your-project/device={デバイス名}/sensor={センサ名}/year={year}/month={month}/day={day}/{hour}-{minutes}.gz
your-project
の部分で格納先のS3バケットを変えるので適宜変更する。
今回想定するIoTデバイスはデバイス名とセンサ名をあらかじめ指定した使い方をするので、Athenaで検索する母数を減らすために先頭で指定する。
AWS IoTで設定するルールクエリステートメントとアクション
- ルールクエリステートメントではS3バケットへの振り分けと、バケットの中で格納するkeyを指定する。
-
your-project
ごとにルールクエリステートメントを作成して振り分けたいS3バケットをアクションで追加する。 - キーに
${topic()}
を指定することでトピック名をそのままS3格納先に指定することができる。Suffixを追加で付与することでタイムスタンプなどもつけることができる。
AWS IoTのルールエンジンの設定
S3の格納先
Athenaのクエリ
- テーブルを最初に作成する
- Hive形式部分に新規追加があればパーティションを更新する。本投稿の例では日付でパーティションを分けているので毎日更新する必要がある。また、デバイスやセンサの追加時にもパーティションの更新を実施する。パーティションの更新をしていないと検索してもデータがヒットしない。
- 検索クエリではHive形式で指定した部分を検索条件にすると良い。
テーブルの作成
CREATE EXTERNAL TABLE IF NOT EXISTS your-project (timestamp string,Value1 string)
PARTITIONED BY(device string,sensor string,year int,month int,day int)ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
LOCATION 's3://your-s3-bucket/your-project/';
パーティション更新
MSCK REPAIR table your-project;
データの検索
SELECT * FROM your-project
WHERE device='sample_device'
AND sensor='sample_sensor'
AND year=2020
AND month=12
AND day=08;