読者です 読者をやめる 読者になる 読者になる

たごもりすメモ

コードとかその他の話とか。

hiveの出力が圧縮される方法がよくわからない、と思っていたら俺があほでした

Hadoop Hive

きわめてざっくり書くと以下のような感じ

  • 同じようなクエリを発行しているふたつの出力の圧縮方法が違う
    • 片方はHDFS上でのファイル全体がgzip圧縮されている (ファイルを見ると 00000_0.gz のようになっている)
    • 片方はレコード/ブロック単位でのgzip圧縮になっている (ファイルを見ると 00000_0 で中身先頭にSequenceFileの部分圧縮用ヘッダが書かれている)
  • そもそもこれは何故起きるのか?
    • 似たようなクエリだが最適化の方法が違うなどの理由でこうなるのか?
    • そもそもファイル全体を gzip 圧縮する方法と SequenceFile 内部でgzip圧縮する方法ってどう指定を変えたらどっちになるの?

hiveむづかしい。

(あとで書いた) TextFile だとファイル全体で圧縮がかかって、SequenceFile だと mapred.output.compression.type の指定に従って圧縮を行うわけですね。SequenceFileを扱う場合はこれを BLOCK とかにしておくと圧縮効率が上がります。というか、そうしないと圧縮効率が下がって悲しいことになります。

ということでした! わかった!

詳細

定期的に他のテーブルから1日分のデータをまとめたりしてdailyのテーブル(のパーティション)を編成してる。流れとしては以下のような感じ。

  1. hourlyでパーティションをつくっているテーブルから24時間分をまとめて daily (full) のテーブルに1パーティションとしてINSERT
  2. daily (full) の1パーティション(1日分)から特定の条件でSELECTをかけ、一部分を抽出して daily (part) のテーブルに1パーティションとしてINSERT

このとき、前者より後者の方がデータは少ない(レコードを選別してるし、フィールドも一部のもののみ取り出している)ので後者のデータサイズが小さくなることを当然期待したが hadoop fs -du してみるとそうなってない。あれー?

ということで調べてみたら、以下のようになっていた。

  • daily (full) の方は各パーティション内のファイルは 00000_0.gz のようなファイル名になっており、ファイル全体がgzip圧縮されている
  • daily (part) の方は各パーティション内のファイルは 00000_0 のようなファイル名になっている
    • 中身を見ると 以下のようなヘッダで始まっている

SEQ"org.apache.hadoop.io.BytesWritableorg.apache.hadoop.io.Text'org.apache.hadoop.io.compress.GzipCodec

まったく同じ設定で連続して発行したふたつのクエリでなぜこうなるのか。テーブル定義は両方とも STORED AS SEQUENCEFILE に

……なってなかった!!!!! ここまで書いて気付いた! daily (full) のテーブルは STORED AS TEXTFILE だった!!!!!!

結論

mapred.output.compression.type はちゃんと BLOCK とかで指定しておきましょう。デフォルトの RECORD はたいへん効率わるいです。