0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

DynamoDBデータのグラフ画像作成(Lambda)

Posted at

はじめに

LambdaとDynamoDBを使用すればIOT用のグラフページを作成できるのではと思ったのでその備忘録。
この記事では図中の「グラフ画像生成」部分を実施。
前回:https://qiita.com/aikawa_YO/items/0fb84aec97e28ea33136
関数URLとLambdaのロール設定は前回と同様。
(今回は読み込みだけなのでLambdaからDynamoDBへの権限はフルアクセスいらなかった。)

Lambda-DB.png

DynamoDBからデータを取得する

データを取得するためにいくつかの方法がありました。

get_item

条件に当てはまるデータ単体を取得する

query

条件に当てはまるデータをすべて取得する
PartitionKeyとSortKeyがある
image.png
上記例ではPartitionKeyがidでSortKeyがtime

PartitionKeyのみ、またはPartitionKeyとSortKey2つを指定する事が可能。
Primary Key = Partition Key
Primary Key = Partition Key + Sort Key

今回のIOT機器の場合、idが機器固有の番号、timeがデータを計測した際の時間となりこの2つの値を合わせてプライマリーキーとなる。

queryではPartitionKeyにより絞り込みを行いSortKeyで整列させ出力する。

scan

すべてのデータを取得

query

下記サンプルプログラムではidが1番のデータをtime降順にて取得している。

response = table.query(
    KeyConditionExpression=Key("id").eq(1),
    ScanIndexForward=False
)

BytesIO(Python)

バイナリデータをメモリ(RAM)上で扱うための機能。
Lambdaではエフェメラルストレージが用意されているのでそちらを使用したほうがよかったかもしれない。

matplotlib(Python)

グラフ画像の作成に使用する。
Lambdaにてmatplotlibを使用する方法は下記記事を参考にさせていただきました。

Lambdaの一般設定

グラフの作図や画像データ処理に処理にメモリが必要であるためある程度増やしておく。
処理に時間がかかるとタイムアウトするためタイムアウト時間も調整する必要がある。
image.png

プログラム全体

import base64
import boto3
import matplotlib.pyplot as plt
from io import BytesIO
from datetime import datetime as dt
from boto3.dynamodb.conditions import Key


def lambda_handler(event, context):
    dynamodb = boto3.resource("dynamodb", region_name='ap-northeast-1')
    table = dynamodb.Table("iot_data")
    response = table.query(
        KeyConditionExpression=Key("id").eq(1),
        ScanIndexForward=False
    )
    
    items = response["Items"]
    
    temps = []
    times = []
    for item in items:
        temps.append(float(item['temperature']))
        times.append(dt.strptime(item['time'], '%Y-%m-%d %H:%M:%S %z'))
    
    fig = plt.figure()
    plt.plot(times, temps)
    
    byte_file = BytesIO()
    fig.savefig(byte_file, format="png")
    png_data = byte_file.getvalue()
    
    plt.close()

    return {
        "statusCode": 200,
        "headers": {"Content-Type": "image/png"},
        "body": base64.b64encode(png_data).decode('utf-8'),
        "isBase64Encoded": True
    }

実行結果

関数URLへアクセスすると↓のように画像が表示される
image.png

BytesIOとエフェメラルストレージどちらが早い?

今回は画像の保存部分にBytesIOを使用しました。(通常であれば画像はS3に保存したりすると思います)

byte_file = BytesIO()
fig.savefig(byte_file, format="png")
png_data = byte_file.getvalue()

よくよく考えるとBytesIOを使用した場合メモリ(RAM)上に保存すると思うのでLambdaの場合はふさわしくないのでは?
エフェメラルストレージに保存したほうがいいかもしれないと思いました。

fig.savefig("/tmp/img.png")
file = open('/tmp/img.png', 'rb')
png_data = file.read()

ただ、実行結果は下記のようにそんなに大差はなかったです。
ふつうにBytesIO使っておけば良さそう

BytesIO
1回目:Duration: 1125.19 ms Billed Duration: 1126 ms Memory Size: 512 MB Max Memory Used: 159 MB Init Duration: 2847.22 ms
2回目:Duration: 422.46 ms Billed Duration: 423 ms Memory Size: 512 MB Max Memory Used: 160 MB

エフェメラルストレージ
1回目:Duration: 1140.78 ms Billed Duration: 1141 ms Memory Size: 512 MB Max Memory Used: 159 MB Init Duration: 2433.66 ms
2回目:Duration: 443.96 ms Billed Duration: 444 ms Memory Size: 512 MB Max Memory Used: 161 MB

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?