4
  1. 我想将来自同一个减速器的两种不同类型的输出写入两个不同的目录。

我可以使用 hadoop 中的多个输出功能来写入不同的文件,但它们都进入同一个输出文件夹。

我想将同一个reduce中的每个文件写入不同的文件夹。

有没有办法做到这一点?

如果我尝试将例如“hello/testfile”作为第二个参数,它会显示无效参数。所以我无法写入不同的文件夹。

  1. 如果上述情况不可能,映射器是否可以从输入文件夹中仅读取特定文件?

请帮我。

提前致谢!


谢谢回复。我能够使用上述方法成功读取文件。但在分布式模式下,我无法这样做。在减速器中,我设置了:

mos.getCollector("data", reporter).collect(new Text(str_key), new Text(str_val));

(使用多个输出,并在 Job Conf:我尝试使用

FileInputFormat.setInputPaths(conf2, "/home/users/mlakshm/opchk285/data-r-00000*");

FileInputFormat.setInputPaths(conf2, "/home/users/mlakshm/opchk285/data*");

但是,它给出了以下错误:

cause:org.apache.hadoop.mapred.InvalidInputException: Input Pattern hdfs://mentat.cluster:54310/home/users/mlakshm/opchk295/data-r-00000* matches 0 files
4

4 回答 4

2

问题 1:将输出文件写入不同的目录 - 您可以使用以下方法进行操作:

1. 使用 MultipleOutputs 类:

您能够使用 MultipleOutputs 创建多个命名输出文件,这真是太好了。如您所知,我们需要在您的驱动程序代码中添加它。

MultipleOutputs.addNamedOutput(job, "OutputFileName", OutputFormatClass, keyClass, valueClass);

API 提供了两种重载的写入方法来实现这一点。

multipleOutputs.write("OutputFileName", new Text(Key), new Text(Value));

现在,要将输出文件写入单独的输出目录,您需要使用带有额外参数的重载写入方法作为基本输出路径。

multipleOutputs.write("OutputFileName", new Text(key), new Text(value), baseOutputPath);

请记住在您的每个实现中更改您的 baseOutputPath。

2. 重命名/移动驱动类中的文件:

这可能是将输出写入多个目录的最简单的方法。使用多个输出并将所有输出文件写入单个输出目录。但是每个类别的文件名需要不同。

假设您要创建 3 组不同的输出文件,第一步是在驱动程序中注册命名的输出文件:

MultipleOutputs.addNamedOutput(job, "set1", OutputFormatClass, keyClass, valueClass);
MultipleOutputs.addNamedOutput(job, "set2", OutputFormatClass, keyClass, valueClass);
MultipleOutputs.addNamedOutput(job, "set3", OutputFormatClass, keyClass, valueClass);

此外,在驱动程序代码中创建不同的输出目录或所需的目录结构,以及实际的输出目录:

Path set1Path = new Path("/hdfsRoot/outputs/set1");
Path set2Path = new Path("/hdfsRoot/outputs/set2");
Path set3Path = new Path("/hdfsRoot/outputs/set3");

最后一个重要步骤是根据名称重命名输出文件。如果工作成功;

FileSystem fileSystem = FileSystem.get(new Configuration);
if (jobStatus == 0) {

        // Get the output files from the actual output path 
        FileStatus outputfs[] = fileSystem.listStatus(outputPath);

        // Iterate over all the files in the output path
        for (int fileCounter = 0; fileCounter < outputfs.length; fileCounter++) {

            // Based on each fileName rename the path.
            if (outputfs[fileCounter].getPath().getName().contains("set1")) {
                fileSystem.rename(outputfs[fileCounter].getPath(), new Path(set1Path+"/"+anyNewFileName));
            } else if (outputfs[fileCounter].getPath().getName().contains("set2")) {
                fileSystem.rename(outputfs[fileCounter].getPath(), new Path(set2Path+"/"+anyNewFileName));
            } else if (outputfs[fileCounter].getPath().getName().contains("set3")) {
                fileSystem.rename(outputfs[fileCounter].getPath(), new Path(set3Path+"/"+anyNewFileName));
            }
        }
    }

注意:这不会给作业增加任何重大开销,因为我们只是将文件从一个目录移动到另一个目录。选择任何特定的方法取决于您的实施的性质。

总而言之,这种方法基本上将所有使用不同名称的输出文件写入同一个输出目录,当作业成功完成时,我们重命名基本输出路径并将文件移动到不同的输出目录。

问题 2:从输入文件夹中读取特定文件:

您绝对可以使用MultipleInputs类从目录中读取特定的输入文件。

根据您的输入路径/文件名,您可以将输入文件传递给相应的 Mapper 实现。

情况 1:如果所有输入文件都在一个目录中:

FileStatus inputfs[] = fileSystem.listStatus(inputPath);
for (int fileCounter = 0; fileCounter < inputfs.length; fileCounter++) {
    if (inputfs[fileCounter].getPath().getName().contains("set1")) {
        MultipleInputs.addInputPath(job, inputfs[fileCounter].getPath(), TextInputFormat.class, Set1Mapper.class);
    } else if (inputfs[fileCounter].getPath().getName().contains("set2")) {
        MultipleInputs.addInputPath(job, inputfs[fileCounter].getPath(), TextInputFormat.class, Set2Mapper.class);
    } else if (inputfs[fileCounter].getPath().getName().contains("set3")) {
        MultipleInputs.addInputPath(job, inputfs[fileCounter].getPath(), TextInputFormat.class, Set3Mapper.class);
    }   
}

情况 2:如果所有输入文件都不在一个目录中:

即使输入文件位于不同的目录中,我们基本上也可以使用上述相同的方法。遍历基本输入路径并检查文件路径名是否匹配标准。

或者,如果文件位于完全不同的位置,最简单的方法是单独添加到多个输入。

MultipleInputs.addInputPath(job, Set1_Path, TextInputFormat.class, Set1Mapper.class);
MultipleInputs.addInputPath(job, Set2_Path, TextInputFormat.class, Set2Mapper.class);
MultipleInputs.addInputPath(job, Set3_Path, TextInputFormat.class, Set3Mapper.class);

希望这可以帮助!谢谢你。

于 2016-05-20T17:11:07.517 回答
1

将 MultipleOutputs 代码复制到您的代码库中并放宽对允许字符的限制。无论如何,我看不出任何有效的限制理由。

于 2012-07-14T04:07:33.273 回答
1

是的,您可以指定输入格式仅处理某些文件:

FileInputFormat.setInputPaths(job, "/path/to/folder/testfile*");

如果您确实修改了代码,请记住 _SUCCESS 文件应在作业成功完成后写入两个文件夹 - 虽然这不是必需的,但它是一种机制,人们可以通过它来确定该文件夹中的输出是否完整,而不是由于错误而“截断”。

于 2012-07-14T11:38:48.887 回答
0

是的,你可以这样做。您需要做的就是为来自 reducer 的特定键/值对生成文件名。

如果你覆盖一个方法,你可以根据你得到的键/值对返回文件名,等等。这是向您展示如何执行此操作的链接。

https://www.google.co.in/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CFMQFjAA&url=https%3A%2F%2Fsites.google.com%2Fsite%2Fhadoopandhive%2Fhome%2Fhow- to-write-output-to-multiple-named-files-in-hadoop-using-multipletextoutputformat&ei=y7YBULarN8iIrAf4iPSOBg&usg=AFQjCNHbd8sRwlY1-My2gNYI0yqw4254YQ

于 2012-07-14T18:24:17.283 回答