我想将映射器输出的一部分写入一个文件夹,比如 HDFS 中的文件夹 A。输出的另一部分,我希望它被reducer处理。这可能吗?我知道多个输出。这可以使用多个输出吗?
谢谢!
是的,可以使用 MultipleOutputs,根据文档,在 map 阶段通过 MultipleOutputs 传递的任何输出都会被 reducer 忽略,所以这正是你想要的。我在我的 GitHub 上写了一个小例子,希望对你有用。
您可以从映射器实现直接将输出写入 HDFS - 只需使用上下文的配置创建一个 FileSystem 对象,然后创建一个文件,写入它并记住将其关闭:
public void cleanup(Context context) {
FileSystem fs = FileSystem.get(context.getConfiguration());
PrintStream ps = new PrintStream(fs.create(
new Path("/path/to/output", "map-output")));
ps.println("test");
ps.close();
}
需要考虑的其他事项 - 每个文件需要在 HDFS 中唯一命名,因此您可以在文件名后加上映射器 ID 号,但您还需要了解推测执行(因为您的映射器任务实例可能在两个位置运行 - 两者尝试写入 HDFS 中的同一文件)。
您通常会从这里抽象出来,因为输出提交程序在 tmp HDFS 目录中创建具有任务 ID 和尝试编号的文件,仅在提交该任务尝试时将其移动到正确的位置和文件名。在运行 map 端(数据写入本地文件系统)而不关闭推测执行或在 HDFS 中创建多个文件(每次尝试之一)时,无法解决此问题。
所以一个更“完整”的解决方案看起来像:
FileSystem fs = FileSystem.get(context.getConfiguration());
PrintStream ps = new PrintStream(fs.create(new Path(
"/path/to/output", String.format("map-output-%05d-%d",
context.getTaskAttemptID().getTaskID().getId(),
context.getTaskAttemptID().getId()))));
ps.println("test");
ps.close();
MultipleOutputs 将帮助您减少边,但我不认为映射边它会起作用,因为没有输出提交者并且工作目录不在 HDFS 中。
当然,如果这只是映射器的工作,那么 MultipleOutputs 就可以了。因此,另一种方法是运行仅地图作业,然后在辅助作业中使用所需的输出部分(使用身份映射器) - 取决于我猜你移动了多少数据。