Athena超便利で活用しているのですが、あるクエリーをかけると「返されたレコードはゼロです(Zero records returned)」というエラーになりました。
このエラーが出る原因はいろいろありますが、今回は「そのものズバリ」なブログやドキュメントが引っ掛からなかったので、過去の自分のためにも記載します。
結論から言うと「マネージメントコンソールからフォルダを作って、そのフォルダ配下をクエリ対象先に指定しようとしたから」でした。
以降、「マネージメントコンソール」は「マネコン」と略します。
返されたレコードはゼロです(Zero records returned) が返るケース
発生し得る一般的な原因は上記の公式ドキュメントにまとめられています。
そして今回、私が発生させた原因は「意図せず0byteのオブジェクトをクエリ対象としていたから」だと考えています。
0byteのオブジェクトをクエリ対象としてしまったらそれはZero records returned返ってきて当たり前なので上記ドキュメントには載っていません。
ハマったケース
手順
- xxxというバケット直下にマネコンからtmpというフォルダを作る
- tmpフォルダの配下にクエリのターゲットとなるオブジェクトを格納する
- LOCATIONを s3://xxx/tmp/ としたテーブルを作成してクエリをかける
期待結果
s3://xxx/tmp/ 配下のオブジェクトにスキャンが走る。
実際の結果
Zero records returned になる。(スキャン0KB)
原因(推測)
S3はキーバリューなので「階層」という概念は本来ないはずですが構造を分かりやすくするためS3コンソールではグループ化の方法としてフォルダの概念をサポートしています。
このためマネコンから「フォルダ」を作成することができます。このとき作成されるのは 「フォルダを表現した0byteのオブジェクト」であるという理解を私はしています
このため手順2.では xxxバケット直下に tmp/
という0byteのオブジェクトができます。
この状態で LOCATIONを s3://xxx/tmp/ と指定すると
「s3://xxx/tmp/」というプレフィックスを指定したつもりが「s3://xxx/tmp/」という0byteのオブジェクトそのものを指定したと解釈され、その0byteのオブジェクトだけスキャンしてZero records returnedになってしまう。
tmp/target.json
のようなオブジェクトを格納していたとしても、それはスキャンされない。
解決方法
マネコンから「フォルダ」を作成しない
たとえば以下のようにcliで直接アップロードする
aws s3 cp ./target.json s3://xxx/tmp/target.json
このやり方であれば
xxxバケットに tmp/target.json
というキーでオブジェクトが作られる
余計な tmp/
という0byteのオブジェクトは作成されない
クエリをかけたときに tmp/
といプレフィックスを持つオブジェクト群にスキャンがかかる。
そもそも何故、マネコンからフォルダ作ったのか
Athenaで分析対象とするようなオブジェクトは普段はプログラムか何かしらのサービスで生成や格納しています。
ただこのときは、手元で編集したファイルで試験的にGlueクローラーやAthenaクエリの挙動を確認するため、マネコンでぽちぽちS3の階層構成を作ってファイルアップロードしました。
厄介だったのはGlueクローラーはこの場合でも配下のファイルを認識して、テーブルを作ってくれたことです。
原因を理解するのにちょっと時間を使ってしまいました