IoTシステムでユースケースの追加によりDynamoDBの再設計が必要となった話

IoTシステムでユースケースの追加によりDynamoDBの再設計が必要となった話

Clock Icon2019.11.26

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは。CX事業本部の若槻です。

今回はAWSのマネージドサービス(IoT Core、Lambda、DynamoDBなど)を利用したIoTシステムの導入にて、追加で発生したビジネス上のユースケースに既存のDynamoDBのテーブル設計では対応ができなくなったため再設計が必要となった、というケースがあったためご紹介します。

どんなシステムか

戸建て住宅の設備(例:玄関の扉)にIoTデバイスを設置し、設備が最後に利用された時刻(例:扉が最後に開閉された時刻)をDynamoDBに記録するサービスを提供するシステムです。

<img src="https://cdn-ssl-devio-img.classmethod.jp/wp-content/uploads/2019/11/4fec0417-47df-4d1d-947d-48d95f879520-640x478.png" />

DynamoDBのプロパティは以下のようになります。

  • placeId(住宅の識別値)
  • placeName(住宅の名称)
  • deviceId(IoTデバイスの識別値)
  • lastOpenCloseAt(最終開閉時刻)

DynamoDBのテーブルには以下のようにデータが格納されます。

| placeId | placeName | deviceId| lastOpenCloseAt |
| --- | :---: | :---: | :---: | --- |
| place001 | 住宅A | device001 | 1574599548 |
| place002 | 住宅B | device002 | 1574600014 |
| place003 | 住宅C | device003 | 1574519724 |

キー・インデックスの指定は以下のようになります。ソートキーの指定はないため、プライマリキーはplaceIdのみとなります。

  • パーティションキー:placeId
  • ソートキー:なし

DynamoDBでデータが更新されるまでの一連の流れは以下のようになります。

  1. IoTデバイスが玄関扉の開閉を検知する
  2. IoTデバイスからAWSへ開閉時刻が送信される
  3. DynamoDBのテーブルに対してパーティションキーであるplaceIdをもとに更新対象のデータの検索が行われる
  4. 更新対象のデータのlastOpenCloseAtが更新される

追加のユースケースと、それによりDynamoDB観点で何が対応できなくなるのか

さて、ここで追加のユースケースとして「表口と裏口の2つの玄関を持つ住宅」に対しても同システムで対応ができるかどうか検討することとなりました。
その場合は表口と裏口のそれぞれの玄関にIoTデバイスを設置し、それぞれの最終開閉時刻を記録する必要があります。

<img class="alignnone size-medium wp-image-497119" src="https://cdn-ssl-devio-img.classmethod.jp/wp-content/uploads/2019/11/b0d236dd-b26c-4634-b61c-fe5e6698e02e-640x422.png" alt="" width="640" height="422" />

当初の想定では、システムの対象となる住宅は1つの玄関(=1つのIoTデバイス)を持つケースのみであり、placeIddeviceId1対1の関係であったため、問題なく対応できていました。
しかし、追加のユースケースでは1つの住宅に2つの玄関があるため、placeIddeviceId1対2の関係となります。この場合はどうなるでしょうか?結論から言いますと、既存のテーブル設計では対応は不可となります。

**[理想]**としては以下のように住宅Cの表口(device003)と裏口(device004)の両方のIoTデバイスのデータが既存のテーブルに登録できると良いでしょう。

| placeId | placeName | deviceId| lastOpenCloseAt |
| --- | :---: | :---: | :---: | --- |
| place001 | 住宅A | device001 | 1574599548 |
| place002 | 住宅B | device002 | 1574600014 |
| place003 | 住宅C | device003 | 1574519724 |
| <span style="color: #d61b09;">place003</span> | <span style="color: #d61b09;">住宅C</span> | <span style="color: #d61b09;">device004</span> | <span style="color: #d61b09;">1574607363</span> |

しかし**[実際]**には以下のように既に登録されているdevice003のデータにdevice004のデータが上書きされる動作となります。

| placeId | placeName | deviceId| lastOpenCloseAt |
| --- | :---: | :---: | :---: | --- |
| place001 | 住宅A | device001 | 1574599548 |
| place002 | 住宅B | device002 | 1574600014 |
| <span style="color: #d61b09">place003</span> | <span style="color: #d61b09">住宅C</span> | <span style="color: #d61b09">device004</span> | <span style="color: #d61b09">1574607363</span> |

これは、プライマリキーであるplaceIdは同じテーブル内で値がユニークである必要があるため、同じデータとして扱われてしまったためです。

よってテーブル設計においてキー・インデックスの指定を以下のように再設計する必要があります。

  • パーティションキー:placeId
  • ソートキー:deviceId

ソートキーにdeviceIdを指定することにより、placeId + deviceIdから成るプライマリキーが追加のユースケースにおいてもユニークな値となるため、既存の設計では対応ができなかったdevice003device004の両方のデータの登録が可能となります。

おわりに

すでにDynamoDBの利用経験がある方にとっては初級レベルの内容のエントリだと思いますが、わたしは業務でAWSに触れるのが初めてであったため既存のテーブル設計で何がだめなのか理解をするのに時間を要しました。

今回のケースを通して、データベースとして概念設計の時点でユースケースの洗い出しを入念に行うことが、拡張性のあるDynamoDBのシステムを作る上で大切であることを実感しました。

参考

以上

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.