hadoop fsコマンドの仕様メモを2つほど

lsとstatでは表示されるタイムスタンプが9時間異なる。

$ hadoop fs -ls /user/hive/warehouse/hoge/
Found 1 items
-rw-r--r--   3 hadoop supergroup        189 2011-10-24 17:45 /user/hive/warehouse/hoge/sequencefile
$ hadoop fs -stat /user/hive/warehouse/hoge/sequencefile
2011-10-24 08:45:29

9時間というとアレですよね。タイムゾーンですね。

hadoop fsコマンドはバックでFsShellを読むのでソースを見てみます。バージョンはCDH3u0です。

  public static final SimpleDateFormat dateForm = 
    new SimpleDateFormat("yyyy-MM-dd HH:mm");
  protected static final SimpleDateFormat modifFmt =
    new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  static final int BORDER = 2;
  static {
    modifFmt.setTimeZone(TimeZone.getTimeZone("UTC"));
  }

hadoop fs -lsはdateFormを、hadoop fs -statはmodifFmtを使います。

SimpleDateFormatはスレッドセーフじゃねえ!っていう突っ込みはおいときますw


hadoop fs -textコマンドはhadoop fs -catと違いSequenceFileの中身も見れる

ヘルプにはこう書かれています。

-cat <src>:     Fetch all files that match the file pattern <src>
                and display their content on stdout.

-text <src>:    Takes a source file and outputs the file in text format.
                The allowed formats are zip and TextRecordInputStream.

text実行時のソースはこうなっています。下から読むといいと思います。

  private class TextRecordInputStream extends InputStream {
    SequenceFile.Reader r;
    WritableComparable key;
    Writable val;

    DataInputBuffer inbuf;
    DataOutputBuffer outbuf;

    public TextRecordInputStream(FileStatus f) throws IOException {
      r = new SequenceFile.Reader(fs, f.getPath(), getConf());
      key = ReflectionUtils.newInstance(r.getKeyClass().asSubclass(WritableComparable.class),
                                        getConf());
      val = ReflectionUtils.newInstance(r.getValueClass().asSubclass(Writable.class),
                                        getConf());
      inbuf = new DataInputBuffer();
      outbuf = new DataOutputBuffer();
    }

    public int read() throws IOException {
      int ret;
      if (null == inbuf || -1 == (ret = inbuf.read())) {
        if (!r.next(key, val)) {
          return -1;
        }
        byte[] tmp = key.toString().getBytes();
        outbuf.write(tmp, 0, tmp.length);
        outbuf.write('\t');
        tmp = val.toString().getBytes();
        outbuf.write(tmp, 0, tmp.length);
        outbuf.write('\n');
        inbuf.reset(outbuf.getData(), outbuf.getLength());
        outbuf.reset();
        ret = inbuf.read();
      }
      return ret;
    }
  }

  private InputStream forMagic(Path p, FileSystem srcFs) throws IOException {
    FSDataInputStream i = srcFs.open(p);

    // check codecs
    CompressionCodecFactory cf = new CompressionCodecFactory(getConf());
    CompressionCodec codec = cf.getCodec(p);
    if (codec != null) {
      return codec.createInputStream(i);
    }

    switch(i.readShort()) {
      case 0x1f8b: // RFC 1952
        i.seek(0);
        return new GZIPInputStream(i);
      case 0x5345: // 'S' 'E'
        if (i.readByte() == 'Q') {
          i.close();
          return new TextRecordInputStream(srcFs.getFileStatus(p));
        }
        break;
    }
    i.seek(0);
    return i;
  }

  void text(String srcf) throws IOException {
    Path srcPattern = new Path(srcf);
    new DelayedExceptionThrowing() {
      @Override
      void process(Path p, FileSystem srcFs) throws IOException {
        if (srcFs.isDirectory(p)) {
          throw new IOException("Source must be a file.");
        }
        printToStdout(forMagic(p, srcFs));
      }
    }.globAndProcess(srcPattern, srcPattern.getFileSystem(getConf()));
  }

text→forMagicと呼び出していきヘッダがSEQだとSequenceFileと判断しTextRecordInputStreamクラスを使います。
コンストラクタでSequenceFile.Readerが使われていることがわかります。
readメソッドを見ると、下記のように出力されることがわかります。

key1 \t value1
key2 \t value2
key3 \t value3

以前HiveのSequenceFileとかパーティションとか - wyukawa’s blogでHiveでSequenceFileを使う場合はkey何でもいいよーって書きました。

HiveでSELECT INSERTする場合は値が入っていないBytesWritableをkeyに使いますのでhadoop fs -textするとkeyが空なのでタブから始まります。

keyに値をセットするとhadoop fs -textした時にkeyも表示されます。SELECTしたときは表示されません。

keyにsampleという文字列をセットした場合はこんな挙動になります。なおhogeテーブルに2つのstringのカラム(値はaとb)があるという前提です。

$ hive -e "select * from hoge"
a	b
$ hadoop fs -text /user/hive/warehouse/hoge/sequencefile
sample    a       b