【问题标题】:Upload data to HDFS with Java API使用 Java API 将数据上传到 HDFS
【发布时间】:2015-09-04 13:17:10
【问题描述】:

我已经搜索了一段时间,但似乎没有一个解决方案适合我。

非常简单 - 我想使用 Java API 将数据从本地文件系统上传到 HDFS。 Java 程序将在已配置为通过 shell 与远程 Hadoop 集群通信的主机上运行(即hdfs dfs -ls 等)。

我的项目中包含以下依赖项:

hadoop-core:1.2.1
hadoop-common:2.7.1
hadoop-hdfs:2.7.1

我的代码如下所示:

 File localDir = ...;
 File hdfsDir = ...;
 Path localPath = new Path(localDir.getCanonicalPath());
 Path hdfsPath = new Path(hdfsDir.getCanonicalPath());
 Configuration conf = new Configuration();
 conf.set("fs.hdfs.impl", org.apache.hadoop.hdfs.DistributedFileSystem.class.getName());
 conf.set("fs.file.impl", org.apache.hadoop.fs.LocalFileSystem.class.getName());
 Filesystem fs = FileSystem.get(configuration);
 fs.getFromLocalFile(localPath, hdfsPath);

本地数据没有复制到Hadoop集群,但是没有报错,也没有抛出异常。我为org.apache.hadoop 包启用了TRACE 日志记录。我看到以下输出:

 DEBUG Groups:139 -  Creating new Groups object
 DEBUG Groups:139 -  Creating new Groups object
 DEBUG Groups:59 - Group mapping impl=org.apache.hadoop.security.ShellBasedUnixGroupsMapping; cacheTimeout=300000
 DEBUG Groups:59 - Group mapping impl=org.apache.hadoop.security.ShellBasedUnixGroupsMapping; cacheTimeout=300000
 DEBUG UserGroupInformation:147 - hadoop login
 DEBUG UserGroupInformation:147 - hadoop login
 DEBUG UserGroupInformation:96 - hadoop login commit
 DEBUG UserGroupInformation:96 - hadoop login commit
 DEBUG UserGroupInformation:126 - using local user:UnixPrincipal: willra05
 DEBUG UserGroupInformation:126 - using local user:UnixPrincipal: willra05
 DEBUG UserGroupInformation:558 - UGI loginUser:<username_redacted>
 DEBUG UserGroupInformation:558 - UGI loginUser:<username_redacted>
 DEBUG FileSystem:1441 - Creating filesystem for file:///
 DEBUG FileSystem:1441 - Creating filesystem for file:///
 DEBUG FileSystem:1290 - Removing filesystem for file:///
 DEBUG FileSystem:1290 - Removing filesystem for file:///
 DEBUG FileSystem:1290 - Removing filesystem for file:///
 DEBUG FileSystem:1290 - Removing filesystem for file:///

谁能帮助我解决这个问题?

编辑 1:(09/15/2015)

我已经删除了 2 个 Hadoop 依赖项 - 我现在只使用一个:

hadoop-core:1.2.1

我的代码现在如下:

File localDir = ...;
File hdfsDir = ...;
Path localPath = new Path(localDir.getCanonicalPath());
Path hdfsPath = new Path(hdfsDir.getCanonicalPath());
Configuration conf = new Configuration();
fs.getFromLocalFile(localPath, hdfsPath);

我之前使用以下命令执行我的应用程序:

$ java -jar <app_name>.jar <app_arg1> <app_arg2> ...

现在我用这个命令执行它:

$ hadoop jar <app_name>.jar <app_arg1> <app_arg2> ...

通过这些更改,我的应用程序现在可以按预期与 HDFS 交互。 据我所知,hadoop jar 命令仅适用于打包为可执行 jar 的 Map Reduce 作业,但这些更改确实骗我的。

【问题讨论】:

  • hadoop 命令在类路径中包含 hadoop 类,如果有必要解压 jar 并重新打包以包含一些库。在 enh 处 haddop 命令将执行 java 命令,但带有额外的对象/配置。
  • 我已经使用 Maven Shade 插件将我的程序打包为一个胖罐子。你指的是别的东西吗?如果是这样,请澄清。

标签: java hadoop hdfs


【解决方案1】:

我不确定您所遵循的方法,但以下是使用 java 库将数据上传到 hdfs 的一种方法:

//imports required 
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;

//some class here .....
Configuration conf = new Configuration();
conf.set("fs.defaultFS", <hdfs write endpoint>);
FileSystem fs = FileSystem.get(conf);
fs.copyFromLocalFile(<src>, <dst>);

此外,如果您在本地有 hadoop conf xml,您可以将它们包含在您的类路径中。然后 hadoop fs details 将在运行时自动获取,您无需设置 "fs.defaultFS" 。此外,如果您在旧的 hdfs 版本中运行,您可能需要使用“fs.default.name”而不是“fs.defaultFS”。如果您不确定 hdfs 端点,通常是 hdfs namenode url。以下是之前类似问题copying directory from local system to hdfs java code

的示例

【讨论】:

  • 我的程序使用 Maven Shade 插件打包为一个胖罐。我注意到,如果我尝试使用 $ java -jar &lt;program_name&gt;.jar 执行 jar,则程序不会按预期执行,但如果我使用 $ hadoop jar &lt;program_name&gt;.jar 执行 jar,它会按照我的意图执行。你知道为什么吗?
【解决方案2】:

两件事:

  1. 如果您要创建 Hadoop 客户端,最好添加 hadoop-client 依赖项。它包括所有子模块所需的依赖项。 https://github.com/apache/hadoop/blob/2087eaf684d9fb14b5390e21bf17e93ac8fea7f8/hadoop-client/pom.xml。除非 Jar 的大小是一个问题,并且如果您非常确定不需要其他依赖项。
  2. 当您使用hadoop 命令执行作业时,它执行的类是RunJar,而不是您的驱动程序类。然后 RunJar 执行你的工作。有关更多详细信息,您可以在此处查看代码:https://github.com/apache/hadoop/blob/2087eaf684d9fb14b5390e21bf17e93ac8fea7f8/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/RunJar.java#L139

如果您查看RunJar 类中的createClassLoader 方法,您会注意到类路径中包含多个位置。

然后,如果您直接使用 java -jar 命令执行您的类,您可能会忽略在 hadoop jar 的 hadoop 中执行作业所需的所有其他步骤正在做。

【讨论】:

  • 感谢您的澄清。让我退后一步:我是否应该使用hadoop jar 命令来运行我的程序?我的程序确实与 HDFS 交互,但它不是 Map Reduce 工作。据我了解,hadoop jar 命令用于运行 Map Reduce 作业。碰巧我的程序代码可以用这个命令正确执行(与java -jar 命令相反),因为某些其他东西被添加到类路径中。
  • 如果您的项目不需要在分布式环境(MapReduce 或 Yarn)中运行,则无需使用 hadoop jar。您只需要确保 hadoop-client 依赖项包含在您的项目中。对我来说,最简单的方法是使用 maven 来管理依赖项。使用以下语句执行项目:mvn exec:java -Dexec.mainClass="com.module.Main"
  • 是的,谢谢你的建议。切换到hadoop-client 后,我最终得到了一个关于HADOOP_HOME 和/或hadoop.home.dir 未设置的IOException。现在我使用的是java -jar 而不是hadoop jar,我是否遗漏了一些需要进行的额外配置?
【解决方案3】:

卡萨,你需要使用方法

public static FileSystem get(URI uri,Configuration conf)

要获取fs,如果使用java -jar 命令,则需要uri 参数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-04-17
    • 2014-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-01
    相关资源
    最近更新 更多