AWS IoT Analytics のデータストアでカスタムパーティションがサポートされました

IoT Analytics のデータストアにカスタムパーティションが設定できるようになりました。クエリのパフォーマンス改善やスキャンコストの削減に活用していきましょう。
2021.06.17

先日、AWS IoT Analytics のアップデートでデータストアのカスタムパーティションが利用できるようになりました。

何がうれしいの?

これまでは、ユーザー側でパーティションを指定することができず、「1日」という固定の設定になっていました。そのため 1 時間分のデータだけクエリを実行したい場合でも無駄なスキャンコストが発生していました。

今回のアップデートで、パーティションを小さく分割できるようになったので、次のようなメリットが出てきました。

  • スキャンするデータ量が少なくなるので利用料金を抑えられる
    • データセットのスキャンコストの削減
  • スキャンサイズが少なくなるのでクエリの実行パフォーマンスが上がる

やってみた

前提

今回は既存のデータフロー(チャネル, パイプライン, データストア)を利用します。既にあるデータストアに対してパーティション設定の変更はできないので、今回はデータストアを作り直しています。

下記では、既存のデータストアを一度削除して新たに作成しています。

01-create-datastore

既存のパイプラインをそのまま使いたかったので、「データストアID」は削除したものと同名とします。

02-enter-store-id

データストアのストレージや IAM Role も既存のデータストアで使っていたものを指定しています。

03-configure-storage

データフォーマットも以前と同じままとします。

04-choose-format

次の画面でようやくカスタムパーティションの設定を行います。「カスタムパーティションの有効化」 にチェックを入れます。データソースとして既存のチャネルを選択しました。

05-enable-custom-partitioning

既存のデータソースを選択した状態で「Sample attributes」 をクリックすると、すでにチャネルに入っているデータがサンプルとして表示されます。

06-sample-attribute

サンプルデータからカスタムパーティションのディメンションに使う項目にチェックを入れます。今回は timestampという項目を使おうと思うので、上部のプルダウンから Add as timestamp partition を選択します。

07-add-timestamp-partition

カスタムパーティションを指定できたら次のような画面が現れます。Attribute nameには先ほど選択したサンプルデータのカラム(timestamp)が自動的に設定されます。今回はタイムスタンプをカスタムパーティションとして設定したのでPartition Typeの欄も自動的に入力されました。

08-set-new-partition

Timestamp formatはサンプルデータに合わせてyyyy-MM-dd HH:mm:ssを指定しています。なお、Dimension nameはタイムスタンプをパーティションとして指定すると自動的に設定されます。

09-timestamp-format

最後のレビュー画面で設定内容を確認してデータセットの作成を実行します。

10-review

確認用のデバイスデータを IoT Analytics に送る

次にデータを送ってみます。今回は 大量にデータを送りたかったのでbasic ingestを使ってデータを IoT Analytics に送信しました。

データの送信は以前ご紹介した 「MQTT X」というクライアントツールのスクリプト機能を使いました。スクリプトでランダムデータを生成して10 秒間隔でデータを送っています。
「MQTT X」の使い方については下記のブログをご参照下さい。

「MQTT X」で利用した JavaScript は下記になります。(コーディングは不慣れなため稚拙なコードである点はご容赦ください)

function random(min, max) {
  return Math.round(Math.random() * (max - min)) + min
}

var d = new Date();
var year  = d.getFullYear();
//var month = d.getMonth() + 1;
var  month = ("0"+(d.getMonth() + 1)).slice(-2);
var day   = d.getDate();
var hour  = ( d.getHours()   < 10 ) ? '0' + d.getHours()   : d.getHours();
var min   = ( d.getMinutes() < 10 ) ? '0' + d.getMinutes() : d.getMinutes();
var sec   = ( d.getSeconds() < 10 ) ? '0' + d.getSeconds() : d.getSeconds();

function handlePayload(value) {
  let _value = value
  if (typeof value == 'string') {
    _value = JSON.parse(value)
  }

  _value.sub_metering_1 = random(10,30)
  _value.sub_metering_2 = random(20,40)
  _value.sub_metering_3 = random(20,40)
  _value.global_active_power = random(0,10)
  _value.global_reactive_power = random(10,30)
  _value.voltage = random(200,250)
  _value.timestamp = year + '-' + month + '-' + day + ' ' + hour + ':' + min + ':' + sec
  _value._id_ = 'KwW37jXxC'
  return JSON.stringify(_value, null, 2)
}

execute(handlePayload)

実際に送信されるデータは下記のようなものになります。

{
  "sub_metering_1": 55,
  "sub_metering_2": 43,
  "sub_metering_3": 12,
  "global_active_power": 7,
  "global_reactive_power": 23,
  "timestamp": "2021-06-15 04:41:28",
  "voltage": 222,
  "_id_": "KwW37jXxC"
}

カスタムパーティションの効果を確認する

繰り返しになりますが今回は次のようにデータを送ってみました。

  • 200 Byte 程度のデータを 10 秒間隔で送信
  • 送信したデータ総数は約3000件
    • 途中で送信間隔を 1秒に変更して送っていました

データを送信後、AWS IoT Analytics のデータセットでクエリを実行してみます。スキャン期間を変えてクエリの実行時間に違いがあるか確認してみました。

16 時台のデータだけスキャン

次の SQLデータセットで指定したカスタムパーティションを使ってクエリを実行します。

SELECT * FROM mystore where __year = 2021 AND __month = 06 AND __day = 15 AND __hour = 16

12-16-query-run

17 時以降の全データをスキャン

少し変えて次の SQLデータセットで 17 時以降全てのデータを対象にクエリを実行してみます。

SELECT * FROM mystore where __year = 2021 AND __month = 06 AND __day = 15 AND __hour >= 17

11-17-query-run

スキャン時間の比較

「16時台」と「17 時以降全て」でクエリの実行時間は次のようになりました。

スキャン回数(回目) 16時台のクエリ時間 17時以降のクエリ時間
1 1535 ms 1913 ms
2 1550 ms 2052 ms
3 1435 ms 2109 ms
4 1291 ms 2253 ms
5 1467 ms 2751 ms
6 1838 ms 2833 ms
7 1485 ms 2535 ms
8 1487 ms 2067 ms
9 1689 ms 1844 ms
10 1416 ms 2368 ms

それぞれの平均は次のとおりです。

16時台のクエリ時間平均 17時以降のクエリ時間平均
1519.3ms 2272.5ms

データ量が少ないので、大きな違いは確認できませんでしたがスキャンサイズが変わったことでクエリパフォーマンスの変化を確認することができたと思います。より大きなデータサイズ(数十GB〜やTBクラス)になると違いが顕著に現れるかと思います。

なお、比較に使ったクエリ時間はデータセットコンテンツに記載のものを採用しました。

13-duration

補足 - データストアの S3 バケット構造

今回のようにタイムスタンプをカスタムパーティションとして作成した場合、データストアの S3 バケットは次のような構成になっていました。

└── your-datastore-bucket
    └── datastore
        └── your-data-store
            └── __dt=2021-06-15\ 00:00:00
                └── __year=2021
                    └── __month=06
                        └── __day=15
                            └── __hour=20

14-datastore-custom-partision-s3

最後に

今回はタイムスタンプを元にパーティションを指定しましたが、カスタム属性をパーティションとすることもできるようなので、後日試してみたいと思います。

以上です。