PoCレベルで作成しているアプリケーションのサンプルデータのデータベースとして、S3に保存したcsvファイルを使ってみました。
S3に保存したcdvファイルは、S3 selectという機能で簡単なSQL操作ができるので、サンプルデータくらいであれば使えるであろうと踏んで実装してみました。
ただ、実際にはS3 selectで利用できるSQL操作は制限が多くあるようです。
さらにS3 selectで大きなデータを取得しようとしてもエラーが生じることが分かりました。
今回は、S3 selectを利用して、not inを含む処理をしようとしたときのエラーとその対策について紹介していきます。
S3 Selectとは?
まずは、S3 Selectについて簡単に紹介していきます。
S3 selectとは、S3バケットに保存したCSVファイルやJSONファイル等のオブジェクトに対して、直接SQL操作を行うことができるサービスです。
コンソール画面からでも簡単に試すことができます。
S3オブジェクトに対して、アクションメニューからS3 selectを使用したクエリを選択します。
あとは、次の画面で入力オブジェクトのファイル形式やヘッダーの有無、区切り文字の設定と出力オブジェクトに対しても設定をします。
SQL操作クエリを実行することでコンソール画面で直接出力結果を得ることが可能です。注意点としては、FROM句がファイル名ではなく、s3object
と固有の値になるくらいです。
今回取得したかったデータ
さて、本題の今回S3 Selecetを利用して実現できなかったことについて紹介していきます。
先ほど紹介したように、S3 selectを利用することで、簡単にクエリ操作を行うことが可能です。
そこで、冒頭でも述べましたが、PoCレベルの開発にあたりS3を簡単なDBとして利用してみようということでS3 SelecetS3を簡単なDBとして利用しています。
SQL操作で生じたエラー
今回は課題一覧のissuesというCSVファイルから、特定のIDに該当するもの以外のアイテムを取得しようとしています。
具体的なコードは以下のようなイメージです。
let excludedIssues = [ issueId, ...checkedIssues ]
const formattedExcludedIssues = `(${excludedIssues.join(', ')})`
const targetIssuesSql = `SELECT id FROM S3Object WHERE id NOT IN ${formattedExcludedIssues} `
const targetIssues = await S3Client
.s3Select(file, targetIssuesSql)
.then(res => {
return res
})
console.log('targetIssues:', targetIssues)
すでにチェック済みのissueは除外する必要があったので、issueId
とcheckedIssues
(チェック済みイシュー)をexcludedIssues
というリストで作成しています。
さらに、SQL操作する際、NOT INは( )で囲まれている必要があるので、formatで変換しています。このタプル型で渡し、WHERE句のNOT IN ()
で除しようとしました。
エラーの内容
ただし、NOT INによるSQL操作がS3 Selcectでは扱うことが出来ず、以下のようなエラーが生じます。
ERROR Thrown unexpected error UnsupportedSyntax: Unsupported syntax at line 1, column 56. Please check the service documentation and try again.
Unsupportedとあるので、サポート外であることがわかりますし、ドキュメントを読めと怒られてしまってますね。
NOT INを使わない対策
サポート外とあるので、まずは今回のエラーについて、まずはドキュメントを確認してみます。
S3 Selecctは初めて利用したのですが、SQL操作としては基本的な操作に限られるようです。
S3 Selectの使い方としては、S3オブジェクトの中身をさっと閲覧する目的で利用するのが主となるようですね。したがって今回やりたいNOT INはサポート外でした。
また、そのほかにも取得データ量に制限があったり、一つのオブジェクトに対してのSQL操作なのでJOINできなかったりと制限はあります。
さて、NOT INはサポート外ですので、今回の場合は他の対策を取る必要があります。 S3 selectを意地でも使っていくということであれば解決策は以下の二つになるでしょう。
- 複数のWHREE句条件を使用する
- データ取得後に絞る
複数の条件を使用する
複数の条件を利用するとは、where句に対して、
where id <> 1 AND id <> 2 AND ....
とつなげていくことです。
実際には、手打ちではなくfor処理などで作っていくことになりますが、やや面倒ですし、ちょっとカッコ悪いですね。
データ取得後に絞る
データ取得後に絞るはその名の通りです。
まずは、データをすべて取得しておいて、その後の結果からLambda関数側で必要な情報に絞ろうというものです。
S3 selectはLambda関数などからSDK等で利用していることが多いと思いますので、処理は問題なさそうです。
別のエラー・制限にも注意
ただ、この場合、他の制限に引っかかることもあります。
そもそもS3 selcetで大量のデータが取得できないようです。先に絞らないとデータ全件が取得できないほどのデータがある場合は、利用できません。
今回は、サンプルデータでそこまで量が多くなかったので、全件取得してからlambda関数で不要なデータを除く処理を実装してひとまず利用できました。
おわりに
S3 Selectを利用してNOT IN
のSQL操作を行いたい時の代替案について紹介しました。
ただ、S3 selectはオブジェクトがどのようなデータが含まれているのか手軽に確認したいという目的が主のような感じですね。
代替案で対策できないこともないですが、処理が増えていることには変わりないので、Lambda関数のレスポンスが低下してしまい、あまりいいものではないかもしれません。
また、アプリを本格的に開発していくには、どちらにせよDBが必要になってくるので、PoC専用だけにS3 Selectを利用するのは、あとから手間が増えそうです。
便利な機能ですが、今回のように簡易DBとして利用したというのは高望みし過ぎで、素直にDynamoDB等を利用した方がよさそうだと改めて感じました。
コメント