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 の関連ソフトウェアが必要であるためです。
設定手順:
- https://github.com/cdarlint/winutils からクラスターバージョンにマッチするフォルダをダウンロードし、パスに日本語や空白がない場所(例: `D:\software\hadoop-3.2.1`)にコピーします。
- Windows の環境変数に `HADOOP_HOME` を追加し、その値を上記のパスに設定し、`%HADOOP_HOME%\bin` を `path` に追加します。
- 上記フォルダの `bin` ディレクトリにある `hadoop.dll` ファイルを `C:\Windows\System32` にコピーします。
- Windows を再起動します。
1 - Maven 依存関係の導入
Maven 依存関係については、以下を参照してください:GitHub
2 - 常用クラスの紹介
HDFS の操作には以下のクラスが主に使用されます:
- `Configuration`:クライアント/サーバーの設定をカプセル化します。
- `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 のアクセス権制御を有効にする方法:
- HDFS クラスターを停止します:
cd ~/bigdata/hadoop-3.2.1 sbin/stop-dfs.sh
- `~/bigdata/hadoop-3.2.1/etc/hadoop/hdfs-site.xml` に以下の設定を追加します:
<property> <name>dfs.permissions.enabled</name> <value>true</value> </property> - HDFS クラスターを再起動します:
cd ~/bigdata/hadoop-3.2.1 sbin/start-dfs.sh
- 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
- コードでファイルをダウンロードします:
@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(); }