HDFS での一般的な Java API 操作

0 - Hadoop 環境の設定 (Windowsシステム)

以下の手順は Windows システムに適用されます。

Windows システムで Hadoop 関連のコードを直接実行すると、`winutils.exe` と `hadoop.dll` ファイルが不足しているというエラーが表示されることがあります。

java.io.IOException: Could not locate executable null\bin\winutils.exe in the Hadoop binaries.
WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable

これは、Hadoop クラスターへのアクセスには Hadoop の関連ソフトウェアが必要であるためです。

設定手順:

  1. https://github.com/cdarlint/winutils からクラスターバージョンにマッチするフォルダをダウンロードし、パスに日本語や空白がない場所(例: `D:\software\hadoop-3.2.1`)にコピーします。
  2. Windows の環境変数に `HADOOP_HOME` を追加し、その値を上記のパスに設定し、`%HADOOP_HOME%\bin` を `path` に追加します。
  3. 上記フォルダの `bin` ディレクトリにある `hadoop.dll` ファイルを `C:\Windows\System32` にコピーします。
  4. Windows を再起動します。

1 - Maven 依存関係の導入

Maven 依存関係については、以下を参照してください:GitHub

2 - 常用クラスの紹介

HDFS の操作には以下のクラスが主に使用されます:

  1. `Configuration`:クライアント/サーバーの設定をカプセル化します。
  2. `FileSystem`:ファイルシステムオブジェクトであり、このオブジェクトを使用してファイル操作を行うことができます。
    FileSystem fs = FileSystem.get(conf);
    

3 - 一般的な API 操作

3.1 ファイルシステムの取得 (重要)

方法1:`FileSystem.get(conf)`

@Test
public void testGetFileSystem1() throws IOException {
    Configuration conf = new Configuration();
    conf.set("fs.defaultFS", "hdfs://hadoop:9000");
    FileSystem fileSystem = FileSystem.get(conf);
    System.out.println(fileSystem);
    fileSystem.close();
}

方法2:`FileSystem.newInstance(conf)`

@Test
public void testGetFileSystem2() throws IOException {
    Configuration conf = new Configuration();
    conf.set("fs.defaultFS", "hdfs://hadoop:9000");
    FileSystem fileSystem = FileSystem.newInstance(conf);
    System.out.println(fileSystem);
    fileSystem.close();
}

3.2 ディレクトリの作成とファイルの書き込み

@Test
public void testPutFile() throws IOException, URISyntaxException {
    FileSystem fileSystem = FileSystem.newInstance(new URI("hdfs://hadoop:9000"), new Configuration());
    boolean result = fileSystem.mkdirs(new Path("/test/input"));
    System.out.println("mkdir result: " + result);
    FSDataOutputStream outputStream = fileSystem.create(new Path("/test/input/hello.txt"), true);
    String content = "hello,hadoop\nhello,hdfs";
    outputStream.write(content.getBytes(StandardCharsets.UTF_8));
    IOUtils.closeQuietly(outputStream);
}

3.3 ファイルのアップロード

@Test
public void testUploadFile() throws URISyntaxException, IOException {
    FileSystem fileSystem = FileSystem.get(new URI("hdfs://hadoop:9000"), new Configuration());
    fileSystem.copyFromLocalFile(new Path("/Users/healchow/bigdata/core-site.xml"),
            new Path("/test/upload/core-site.xml"));
    fileSystem.close();
}

3.4 ファイルのダウンロード

HDFS URL で InputStream を開く方法:

@Test
public void testDownFileByUrl() throws IOException {
    URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
    InputStream inputStream = new URL("hdfs://hadoop:9000/test/input/hello.txt").openStream();
    FileOutputStream outputStream = new FileOutputStream("/Users/healchow/bigdata/test/hello.txt");
    IOUtils.copy(inputStream, outputStream);
    IOUtils.closeQuietly(inputStream);
    IOUtils.closeQuietly(outputStream);
}

FileSystem で InputStream を開く方法:

@Test
public void testDownloadFile() throws URISyntaxException, IOException {
    FileSystem fileSystem = FileSystem.get(new URI("hdfs://hadoop:9000"), new Configuration());
    FSDataInputStream inputStream = fileSystem.open(new Path("/test/input/hello.txt"));
    FileOutputStream outputStream = new FileOutputStream("/Users/healchow/bigdata/test/hello1.txt");
    IOUtils.copy(inputStream, outputStream);
    IOUtils.closeQuietly(inputStream);
    IOUtils.closeQuietly(outputStream);
    fileSystem.close();
}

FileSystem#copyToLocalFile() 方法:

@Test
public void testDownloadFileByCopyTo() throws URISyntaxException, IOException, InterruptedException {
    FileSystem fileSystem = FileSystem.get(new URI("hdfs://hadoop:9000"), new Configuration(), "root");
    fileSystem.copyToLocalFile(new Path("/test/input/hello.txt"),
            new Path("/Users/healchow/bigdata/test/hello2.txt"));
    fileSystem.close();
}

3.5 HDFS ファイルの列挙

@Test
public void testListFiles() throws URISyntaxException, IOException {
    FileSystem fileSystem = FileSystem.get(new URI("hdfs://hadoop:9000"), new Configuration());
    RemoteIterator<LocatedFileStatus> iterator = fileSystem.listFiles(new Path("/test"), true);
    while (iterator.hasNext()) {
        LocatedFileStatus fileStatus = iterator.next();
        System.out.println("filePath: " + fileStatus.getPath());
        BlockLocation[] blockLocations = fileStatus.getBlockLocations();
        for (BlockLocation blockLocation : blockLocations) {
            String[] hosts = blockLocation.getHosts();
            for (String host : hosts) {
                System.out.println("blockHost: " + host);
            }
        }
        System.out.println("blockSize: " + blockLocations.length);
    }
}

4 - HDFS のアクセス権制御

API の練習から、`fs.defaultFS` 設定項目を取得すれば、クラスターにアクセスできる誰でも HDFS 上のデータを読み書きできることを確認できます。これにより、データの安全性が保証されません。

HDFS のアクセス権制御を有効にする方法:

  1. HDFS クラスターを停止します:
    cd ~/bigdata/hadoop-3.2.1
    sbin/stop-dfs.sh
    
  2. `~/bigdata/hadoop-3.2.1/etc/hadoop/hdfs-site.xml` に以下の設定を追加します:
    <property>
        <name>dfs.permissions.enabled</name>
        <value>true</value>
    </property>
    
  3. HDFS クラスターを再起動します:
    cd ~/bigdata/hadoop-3.2.1
    sbin/start-dfs.sh
    
  4. HDFS クラスターにテストファイルをアップロードし、そのファイルの権限を `600` に変更します:
    cd ~/bigdata/hadoop-3.2.1/etc/hadoop
    hdfs dfs -mkdir /test/config
    hdfs dfs -put *.xml /test/config
    hdfs dfs -chmod 600 /test/config/core-site.xml
    
  5. コードでファイルをダウンロードします:
    @Test
    public void testAccessControl() throws Exception {
        FileSystem fileSystem = FileSystem.get(new URI("hdfs://hadoop:9000"), new Configuration(), "testuser");
        fileSystem.copyToLocalFile(new Path("/test/config/core-site.xml"),
                new Path("file:/Users/healchow/bigdata/core-site.xml"));
        fileSystem.close();
    }
    

タグ: HDFS Java Apache Hadoop filesystem configuration

7月28日 00:23 投稿