Hadoop MultipleOutPutFormat和Join Query

时间:2012-03-23 13:58:24

标签: hadoop

我正在处理一个hadoop任务,该任务之前填充了目录中的几个文件,如

部分邻 第1部分 部分-2

由于需要,我修改了此任务,并使用MultipleOutputs捕获更多输出。所以现在目录结构看起来像

部分-0 第1部分 第2部分 输出-1 输出-2- 输出-3

问题:早期的几个作业正在使用此目录进行地图侧外连接,但现在作业必须只接受part- *文件进行连接并丢弃其余文件。

我尝试将输入作为“,”分隔的目录 即 / part-1, / part-2,* / part-3

并按照以下表达式 jobConf.set(“mapred.join.expr”,CompositeInputFormat.compose(outer,                 KeyValueTextInputFormat.class,path []))

现在我的路径[]包含5个enalres,其中ealier曾经是3,在某种程度上,起始三个索引有 / part-1, / part-2,* / part-3路径和像以前一样休息两个。

我不确定我是否正确这样做,请建议我应该怎么做才能使这个连接工作,因为它以前没有输出*文件工作。

使用上述方法抛出以下异常。

java.io.IOException:来自子1的不一致的分割基数(12/6)     org.apache.hadoop.mapred.join.Parser $ CNode.getSplits(Parser.java:369)     org.apache.hadoop.mapred.join.CompositeInputFormat.getSplits(CompositeInputFormat.java:117)     org.apache.hadoop.mapred.JobClient.writeOldSplits(JobClient.java:810)     org.apache.hadoop.mapred.JobClient.submitJobInternal(JobClient.java:781)     org.apache.hadoop.mapred.JobClient.submitJob(JobClient.java:730)

JobConf值如下。

 jobConf.setMapperClass(MyMapper.class);
    jobConf.setReducerClass(MyReducer.class);

  String[] foldersToJoin = StringUtils.split(getInputString(), Constants.COMMA);
    Path[] pathsToJoin =  new Path[foldersToJoin.length];
    int i = 0;
    for(String folder : foldersToJoin){
        pathsToJoin[i++] = new Path(folder);
    }

 FileOutputFormat.setOutputPath(jobConf, new Path("/MyOutPUT"));

    jobConf.setInputFormat(CompositeInputFormat.class);
    jobConf.set("mapred.join.expr", CompositeInputFormat.compose(Constants.OUTER_JOIN_OP,
            KeyValueTextInputFormat.class, pathsToJoin));

    jobConf.setOutputFormat(TextOutputFormat.class);
    jobConf.setOutputKeyClass(Text.class);
    jobConf.setOutputValueClass(Text.class);

    MultipleOutputs.addNamedOutput(jobConf, CHANGE_SET_A,
            TextOutputFormat.class, Text.class, Text.class);
    MultipleOutputs.addNamedOutput(jobConf, CHANGE_SET_B,
            TextOutputFormat.class, Text.class, Text.class);
    MultipleOutputs.addNamedOutput(jobConf,CHANGE_SET_C,
            TextOutputFormat.class, Text.class, Text.class);
    MultipleOutputs.addNamedOutput(jobConf, CHANGE_SET_D,
            TextOutputFormat.class, Text.class, Text.class);

我将文件夹中的所有文件追加为“,”分隔后的字符串以下是代码

  mapred.join.expr = CompositeInputFormat.compose(Constants.OUTER_JOIN_OP,
        KeyValueTextInputFormat.class, pathsToJoin)

   where pathsToJoin =  new Path[]{new Path["/home/hadoop/folder1/part-1"],
  new Path["/home/hadoop/folder1/part-2"],new Path["/home/hadoop/folder1/part-3"],
   new Path["/home/hadoop/folder2"],new Path["/home/hadoop/folder3"] }

所以基本上我只想加入folder1中存在的part- *文件和folder2以及folder3

任何文档或此类场景的任何链接都会有很大的帮助。

1 个答案:

答案 0 :(得分:3)

好的,我想我现在明白这一点。

您已执行了许多将其内容输出到文件夹的作业:

job1 -> folder1
job2 -> folder2
job3 -> folder3

现在,您希望使用CompositeInputFormat合并每个文件夹中的每个part-r-x的输出,并在单个映射器中处理

map0 - merged contents of folder1/part-r-0, folder2/part-r-0, folder3/part-r-0
map1 - merged contents of folder1/part-r-1, folder2/part-r-1, folder3/part-r-1
.. and so on ..

你所增加的复杂性是一个或多个作业使用的是MultipleOutputs,所以不是在folder1中的part-r-x文件,而是

job1 -> folder1/part-x and folder1/output-x

当你来使用CompositeInputFormat时,这是错误的,因为folder1的文件多于folder2和3

在这种情况下,我认为您需要修改mapred.join.expr值以使用一些全局:

// use glob for folder1, to only include the part-x files (ignoring the output-x files)
CompositeInputFormat.compose(Constants.OUTER_JOIN_OP, KeyValueTextInputFormat.class,
   new Path[] {
       new Path('folder1/part-*'),
       new Path('folder2/part-r-*'),
       new Path('folder3/part-r-*'),
   });