Treasure Data - Support Engineering Team blog

トレジャーデータのサポートエンジニアリングチームのブログです。

NumberFormatExceptionによりファイルをインポートできない

こんにちは。Treasure Dataの小嶋です。
今回はお問合せいただくことが多い NumberFormatException というエラーについて解説します。

事例

例えばAWS S3からのファイルインポートジョブが失敗したとします。
そのような場合はまずジョブのOutput Logsを確認してみましょう。
実際に確認してみると、下記のようなエラーが返されていることがあります。

   :
Caused by: org.embulk.parser.csv.CsvParserPlugin$CsvRecordValidateException: java.lang.NumberFormatException: For input string: "xxx"
   :

私の方でSourceを実行してS3からインポートを行い、エラーを再現してみました。
手順はこちらに沿っています。

Amazon S3 Import Integration - Integrations - Treasure Data Product Documentation

下のスクリーンショットを見てください。

Caused by: java.lang.NumberFormatException: For input string: "20歳" というエラーでジョブが失敗していることがわかります。

原因

この例ではインポートするデータのカラム(列)が数値型であるにもかかわらず、漢字の"歳"を含めた"20歳"という文字列をインポートしようとしているためにエラーとなっています。
NumberFormatException は文字通り、数値の形式がおかしいということを意味しています。

エラーとなった行はログ上に表示されており、 今回の例では対象行の内、"20歳"というデータが入っているのは4番目のカラムになるので、その型に着目します。

やはり Age カラムが long(数値)型であることが確認できました。

対策

上述の通り、数値型と文字列型の乖離によって問題が起こってしまっています。
今回の対策としては主に次の3点が考えられます。

カラムを文字列としてインポートするよう定義する

Sourceの設定からカラムの型をstring(文字列型)にすることにより、乖離を解消し問題を回避できます。

ただし、型の変換により運用に支障が生じないかは十分に注意してください。
例えば数値として行われていたValidationが行われなくなるので、数値以外の文字も素通りするようになってしまいます。

CSVファイルを修正して数値以外の文字を取り除く

数値以外を取り除き、有効な値に変換します。

無効なレコードをスキップする

一部のSourceの設定には無効なレコードをスキップしてジョブを進めるか決定する項目があります。
S3の場合は Stop on invalid record?: がこれにあたり、ONの場合、エラーによってジョブが止まってしまいます。
Validationに抵触した無効な値を持つレコードをインポートしない ということが許容できるのであれば、OFFにすることでジョブが進むようになります。
(ちなみにこちらはEmbulkのCSV Parserという機能を用いて実現しています。)

その他

このエラーは汎用的なものであり、S3のみならずGoogle SpreadsheetやGCSからのインポートでも発生します。
また数値と文字列のみでなく、例えば整数(long)と小数(double)のような組み合わせでも発生するので注意してください。
こちらに遭遇したら、まずはインポート元データの型とテーブルのカラムの型を確認するよう覚えておくと良いでしょう。