DynamoDB.batchWriteItem()

AWS Lambdaを使っていて、node.jsからDynamoDBの値を更新しようとしたところちょっとハマったのでメモ。

■ 環境

  • Node.js 8.10
  • AWS Lambda
  • AWS DynamoDB

■ batchWriteItem()

マニュアルを見ていて、`batchWriteItem()`を知った。複数件を操作できるので便利そうだ、と思い早速やってみた。試しに10件更新はうまくいったので100件更新をしようとしたところエラー…。何か間違えたかな?とソースを確認するも問題はなさそう。

マニュアルを再度確認すると下記の記載があった。

* There are more than 25 requests in the batch.

これに引っかかっていたようである。

25件毎の実行に修正したところ問題なく操作ができた。

以上。

Lambda + node + Athena

表題の環境でハマったのでメモとして残しておく。

■ 環境

  • Node.js 8.10
  • AWS Lambda
  • AWS Athena

■ node

新規でLambdaの関数を”一から作成“で作成した際に、下記のコードが作成されたのでこれを元に処理を追加していった。

exports.handler = async (event) => {
    // TODO implement
    return 'Hello from Lambda!'
};

LambdaからAthenaに`startQueryExecution`でクエリを実行させ、S3にCSVが作成された、満足だ、と安心し更に実装を進めていたら、`startQueryExecution`の箇所はほぼ修正していないのに実行ができなくなってしまった…。その後、ファイルのversionを戻しても実行がされない…。`listNamedQueries`を実行してみても結果を得られない…。

  1. 実行できた時点のversionを再実行
  2. `startQueryExecution`を`listNamedQueries`にして実行
  3. 関数を新規に作成して実行

ここまで実行してもやはり実行はできなかった。エラーも出ていない、CloudWatchログで見ても実行時のエラーは出ていない。手詰まり…となったがふと思いたってランタイムを”Node.js 6.10“にして実行してみた。実行してみるとエラーが発生。`async`がダメというような内容であった。

従って、上記のサンプルでいうと下記のように修正した。

exports.handler = (event) => {
    // TODO implement
    return 'Hello from Lambda!'
};

実行できてしまった…。`listNamedQueries`も`startQueryExecution`も問題なく実行ができた。

もしや?と思いこのソースのままランタイムを”Node.js 8.10“に変更しても問題なく実行ができた。

変な箇所にハマって時間をくってしまったので原因を深く追求するのはやめて実装を進めることにする。

以上。

count(distinct (case when … then … end))

SQLにおいて表題の件。自身はAthenaでとても重宝した。条件に合致した中での一意な数を取得したい。

■ 環境

  • Amazon Athena

■ count(distinct)

Athenaを利用しているので、読み込むデータ量も減らしたいしクエリを実行する対象は減らしたい。なので1回のクエリ実行で必要な情報を得たい。複数の条件で`count()`を取得したいが、これは以前のエントリで述べた通り。今回はさらに条件を絞った状態で`distinct`の値を取得したかった。

SELECT
  regist_date,
  count(1) as total,
  count(column1 < 10 or null) as count1, count(column1 >= 10 or null) as count2,
  count(distinct groupid) as group_count1,
  count(distinct (case when column1 < 10 then groupid end)) as group_count2, count(distinct (case when column1 >= 10 then groupid end)) as group_count3,
FROM testtable
GROUP BY regist_date

上記のようなSQLにすることで1度のクエリ実行で自身が得たいデータは全て取得できるようになった。

group_count1“は全体における”groupid“の`distinct`の値。一意な`groupid`の数を取得できる。

group_count2“は、`column1 < 10`の条件に合致した中での一意な`groupid`の数を取得できる。

group_count3“は…以下略。

以上。

■ 関連

複数条件のcount()

S3ライフサイクル

表題の件でゴミを削除することにした。

■ 環境

  • AWS S3

■ ライフサイクル

ライフサイクルでは、一定期間経過後、オブジェクトをGlacierに移動させたりすることができる。今回は該当バケット内に作成された全てのオブジェクトを対象に、作成されて1週間以上経過後のオブジェクトを破棄するようにした。Management Consoleから設定を行ってみる。

該当のバケットを表示後、上部の”管理“より”ライフサイクルルールの追加“を実施する。

ルール名は自身が判別つくわかりやすいもので構わない。フィルターは今回は使用していないが、該当のprefix配下のオブジェクトのみが対象である場合にはここで指定する。

今回はGlacierへの移行ではないのでここはスキップする。

現行バージョン“のみチェックしている。これは該当のバケットではバージョン設定を使用していないからである。”オブジェクトの現行バージョンを失効する“にチェックを入れ、日数は”7“としている。”不完全なマルチパートアップロードをクリーンアップする“も一応チェックを入れておいた。日数はデフォルトままの”7“である。

最後は内容を確認し保存して完了である。

実行されるタイミングはよくわからないが、新たなオブジェクトを追加したタイミングとかであろうか。まぁ自身にとっては不要なファイルを削除してほしいだけなので実行されるタイミングはなんであろうと問題ない。

以上。

CONCAT & CAST & LPAD

Amazon Athenaで表題の関数について。Amazon Athenaに限った話ではなくSQLの話だけれども…。

■ 環境

  • Amazon Athena

■ きっかけ

やりたいこととしては単純に『カラムの値を連結したい』ということだけのはずだった。もうずっと単純なSQLしか書いていなかったのでここら辺の関数についていろいろ忘れておりはまってしまった。

■ CONCAT

文字列として連結したいんだから、”CONCAT“でいけるだろうと思い試してみたところ、下記のエラーが出た。

Error running query: SYNTAX_ERROR: line 1:185: Unexpected parameters (integer) for function concat. Expected: concat(array(E), E) E, concat(E, array(E)) E, concat(array(E)) E, concat(varchar)

あれ?と思いドキュメントを見ていると下記を発見。

Concatenating Arrays
https://docs.aws.amazon.com/ja_jp/athena/latest/ug/concatenating-arrays.html

いややりたいことは”文字列“としての連結であって、配列の連結ではない。ということでこれは違う。もう一度エラーメッセージをよく見てみると下記の通り。

concat(varchar)

できるはずである。としばし考えて気がついた。対象のカラムの型が”int“であった。では”CAST“を挟めば良いのか。ということで下記のような感じになった。

select concat(cast(year as varchar), cast(month as varchar), cast(day as varchar)) ...

しかし得られた結果がこれでは微妙であった。”2018316“。”0“パディングしなければならない。”LPAD“の出番である。”LPAD“だから戻ってくるのは”varchar“だよね、と思い下記のように書き換えた。

select concat(cast(year as varchar), lpad(month, 2, '0'), lpad(day, 2, '0')) ...

実行すると下記のようなエラーが…。

Error running query: SYNTAX_ERROR: line 1:215: Unexpected parameters (integer, integer, varchar(1)) for function lpad. Expected: lpad(varchar(x), bigint, varchar(y))

これもエラーログをよく読んでみれば解決した。ここも”CAST“が必要であった。

最終的に下記で思い通りの結果を得られた。

select concat(cast(year as varchar), lpad(cast(month as varchar), 2, '0'), lpad(cast(day as varchar), 2, '0')) ...

以上。