HDFS findコマンドについて


こんばんは。Hadoopによくパッチを投稿してる[@ajis_ka](https://twitter.com/ajis_ka)です。早速ですがHDFS findコマンドについて紹介します。

## Hadoop 2.6.0以前では使えない

現状の最新リリース(2.6.0)ではfindコマンドは存在せず、HDFS内のファイルを検索するためにはSolrを使う必要がありました。(参考:[Cloudera Search HDFSFindTool](http://www.cloudera.com/content/cloudera/en/documentation/core/latest/topics/search_hdfsfindtool.html))

## Hadoop 2.7.0以降で使えるようになる

しかし、Hadoopの次のバージョン(2.7.0)からは、HDFS findコマンドが標準で使えるようになります。[HADOOP-8989](https://issues.apache.org/jira/browse/HADOOP-8989)で開発されていましたが、チケットが登録されてから6年以上かかってようやくコミットされました。(自分でビルドしたtrunkの)[ドキュメント](http://aajisaka.github.io/hadoop-project/hadoop-project-dist/hadoop-common/FileSystemShell.html#find)によると、現時点では`-name`, `-iname`, `-print`, `-print0`オプションしか使えませんが、その他のオプションも追加されていく予定です。

* 正確に言うと、追加できるように開発がんばります。

## Hadoop 2.6.0で使うための手順

Hadoop 2.7.0は今年中か、来年頭にリリースされると思いますが、待ちきれないせっかちな人のために、既にリリース済のHadoop 2.6.0にパッチを当てる手順を紹介します。(追記: Hadoop 2.5.2でも同じ手順でパッチ適用可能です)

1. [Download](http://www.apache.org/dyn/closer.cgi/hadoop/common/)にアクセスして、hadoop-2.6.0-src.tar.gzをダウンロード、解凍して適当なディレクトリに配置する
2. [BUILDING.txt](https://git-wip-us.apache.org/repos/asf?p=hadoop.git;a=blob;f=BUILDING.txt)に従って、必要なライブラリをインストールする。[Hadoop Wiki](http://wiki.apache.org/hadoop/HowToContribute#Build_Tools)も参考にするとよい。
3. [パッチ](https://issues.apache.org/jira/secure/attachment/12667105/HADOOP-8989.patch)をダウンロードする。
4. ダウンロードしてきたパッチを適用し、ビルドする。

```bash:
$ cd hadoop-2.6.0-src
$ patch -p0 < /path/to/HADOOP-8989.patch 
patching file hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/Command.java
Hunk #1 succeeded at 64 (offset -1 lines).
Hunk #2 succeeded at 122 (offset -1 lines).
Hunk #3 succeeded at 315 (offset -4 lines).
Hunk #4 succeeded at 326 (offset -4 lines).
patching file hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/CommandFactory.java
patching file hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/FsCommand.java
patching file hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/find/And.java
patching file hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/find/BaseExpression.java
patching file hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/find/Expression.java
patching file hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/find/ExpressionFactory.java
patching file hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/find/FilterExpression.java
patching file hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/find/Find.java
patching file hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/find/FindOptions.java
patching file hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/find/Name.java
patching file hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/find/Print.java
patching file hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/find/Result.java
patching file hadoop-common-project/hadoop-common/src/site/apt/FileSystemShell.apt.vm
Hunk #1 succeeded at 232 (offset 2 lines).
patching file hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/MockFileSystem.java
patching file hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestAnd.java
patching file hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestFilterExpression.java
patching file hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestFind.java
patching file hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestHelper.java
patching file hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestIname.java
patching file hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestName.java
patching file hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestPrint.java
patching file hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestPrint0.java
patching file hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/find/TestResult.java
patching file hadoop-common-project/hadoop-common/src/test/resources/testConf.xml
Hunk #1 succeeded at 964 (offset 16 lines).
patching file hadoop-hdfs-project/hadoop-hdfs/src/test/resources/testHDFSConf.xml
$ mvn package -Pdist,native -Dtar -DskipTests
(以下略)
```

* `-Pdist,native`の部分は、`-Pdist`のみでもよいです。(Native Libraryをビルドするかどうかの違い)

うまくいけば、`hadoop-dist/target`配下に`hadoop-2.6.0.tar.gz`が配置されているはずです。

* だめだったら、必要な正しいバージョンのライブラリがインストールされているか確認しましょう。
* Hint:

  * Apache Mavenは3.0系ですか?
  * Protocol Buffersは2.5.0ですか?

あとは、(今年になって書き直した)[公式のマニュアル](http://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-common/SingleCluster.html)を見るか、[昨年のAdvent Calendarの記事](http://qiita.com/ajis_ka/items/4d0373c68c2906c2bf3a#3-3)を参考にセットアップしてください。すると、あら不思議! findコマンドが使えるようになっているはずです。

```xml:
# hadoop version
Hadoop 2.6.0
Subversion Unknown -r Unknown
Compiled by aajisaka on 2014-12-04T10:39Z
Compiled with protoc 2.5.0
From source with checksum e62c297fa67acce70172b70aa8d4f5a
This command was run using /usr/local/hadoop-2.6.0/share/hadoop/common/hadoop-common-2.6.0.jar
# hdfs dfs -ls .
Found 11 items
drwxr-xr-x   - root supergroup          0 2014-11-13 00:17 .hiveJars
-rw-r--r--   1 root supergroup         30 2014-11-12 22:54 airport.txt
drwxr-xr-x   - root supergroup          0 2014-06-05 09:35 child
drwxr-xr-x   - root supergroup          0 2014-06-05 09:35 child2
drwxr-xr-x   - root supergroup          0 2014-06-06 02:18 dir1
drwxr-xr-x   - root supergroup          0 2014-06-05 09:09 dir2
drwxr-xr-x   - root supergroup          0 2014-06-06 03:31 dirToAggregate
-rw-r--r--   1 root supergroup        284 2014-11-12 22:54 flight.txt
drwxr-xr-x   - root supergroup          0 2014-06-17 11:39 sbin
-rw-r--r--+  1 root supergroup       1749 2014-06-17 11:39 test
-rw-r-xr--+  1 root supergroup       1749 2014-06-19 09:03 test2
# hdfs dfs -find / -name "dir*"
/user/root/dir1
/user/root/dir2
/user/root/dirToAggregate
```

相対パス指定だと、相対パスで出力されます。

```xml:
# hdfs dfs -find . -name "dir*"
dir1
dir2
dirToAggregate
```

さらに、Hadoop 2.5.0から追加された、OfflineImageViewerのWebHDFS read-only REST APIと連携してみます。

```xml:
# hdfs oiv -i fsimage_0000000000000004494
14/12/04 23:53:28 INFO offlineImageViewer.FSImageHandler: Loading 3 strings
14/12/04 23:53:28 INFO offlineImageViewer.FSImageHandler: Loading 171 inodes.
14/12/04 23:53:28 INFO offlineImageViewer.FSImageHandler: Loading inode references
14/12/04 23:53:28 INFO offlineImageViewer.FSImageHandler: Loaded 0 inode references
14/12/04 23:53:28 INFO offlineImageViewer.FSImageHandler: Loading inode directory section
14/12/04 23:53:28 INFO offlineImageViewer.FSImageHandler: Loaded 53 directories
14/12/04 23:53:28 INFO offlineImageViewer.WebImageViewer: WebImageViewer started. Listening on /127.0.0.1:5978. Press Ctrl+C to stop the viewer.
```

別ウィンドウを立ち上げて、findコマンドを実行してみます。

```xml:
# hdfs dfs -find webhdfs://127.0.0.1:5978/ -name "dir*"
webhdfs://127.0.0.1:5978/user/root/dir1
webhdfs://127.0.0.1:5978/user/root/dir2
webhdfs://127.0.0.1:5978/user/root/dirToAggregate
```

なんと、起動しているNameNodeに全く負荷を与えることなく、検索することができました。