Java 按键合并选项卡分隔的文件

Java 按键合并选项卡分隔的文件,java,hadoop,mapreduce,Java,Hadoop,Mapreduce,我有三个MapReduce作业,它们生成制表符分隔的文件,并对相同的文件进行操作。第一个值是键。这三个乔布斯的每一项产出都是如此 我现在想做的是,使用MapReduce将这些文件按键“缝合”在一起。最好的映射器输出和减速机输入是什么?我尝试使用ArrayWritable,但由于无序,对于某些记录,ArrayWritable from 1 file位于第三位,而不是第二位 我想要这个: Key \t Values-from-first-MR-job \t Values-from-second-MR

我有三个MapReduce作业,它们生成制表符分隔的文件,并对相同的文件进行操作。第一个值是键。这三个乔布斯的每一项产出都是如此

我现在想做的是,使用MapReduce将这些文件按键“缝合”在一起。最好的映射器输出和减速机输入是什么?我尝试使用ArrayWritable,但由于无序,对于某些记录,ArrayWritable from 1 file位于第三位,而不是第二位

我想要这个:

Key \t Values-from-first-MR-job \t Values-from-second-MR-job \t Values-from-third-MR-job
这对于所有的记录应该是相同的。但是,正如我所说的,由于洗牌,有时一些记录会出现这种情况:

Key \t Values-from-third-MR-job \t Values-from-first-MR-job \t Values-from-second-MR-job

我应该如何设置映射器和还原器来修复此问题?

可以对发出的值进行简单的标记,因为只涉及三种类型的文件。在“地图提取”中,提取拆分的路径,确定其位置并为该值添加合适的前缀。为清楚起见,假设输出在3个目录中:

  • 路径1/mr_out_1
  • 路径2/mr_out_2
  • 路径3/mr_out_3
  • 对所有这些路径使用
    TextInputForamt
    ,在
    map
    中,您将执行以下操作:

    String[] keyVal = value.spilt("\t",2);
    
    Path filePath = ((FileSplit) context.getInputSplit()).getPath();
    String dirName = filePath.getParent().getName().toString();
    
    Text outValue = new Text();
    if(dirName.equals("mr_out_1")){
        outValue.set("1_" + keyVal[1]);
    } else if(dirName.equals("mr_out_2")){
        outValue.set("2_" + keyVal[1]);
    } else {
        outValue.set("3_" + keyVal[1]);
    }
    
    context.write(new Text(keyVal[0]), outVal);
    
    如果所有文件都在同一目录中,请使用文件名而不是目录名。然后根据名称识别标志(正则表达式匹配可能合适):

    reduce
    中,只需将传入值放入列表并排序即可。休息很简单

    List<String> list = new ArrayList<String>(3);
    for(Text v : values){
        list.add(v.toString());     
    }
    Collections.sort(list);
    
    StringBuilder builder = new StringBuilder();
    for(String s : list){
        builder.append(s.substring(2)+"\t");    
    } 
    
    context.write(key, new Text(builder.toString().trim()));
    
    List List=newarraylist(3);
    用于(文本v:值){
    添加(v.toString());
    }
    集合。排序(列表);
    StringBuilder=新的StringBuilder();
    用于(字符串s:列表){
    附加(s.substring(2)+“\t”);
    } 
    write(键,新文本(builder.toString().trim());
    
    我认为这会达到目的。请记住,如果文件超过9个(按字母顺序排列),则
    Collection.sort
    策略将失败。然后,您可以单独提取标记,将其转换为
    整数
    ,并使用
    树映射
    进行排序


    注意:以上所有代码段都使用了新的API。我没有使用IDE编写这些代码,所以可能存在的语法错误很少。我又一次在写作中没有遵循适当的惯例。假设
    map
    的outKey可以是类成员,使用
    outKey.set(keyVal[0])
    可以删除
    文本
    对象创建开销

    可能您正在寻找的是二次排序和值中的手动前缀(每个MR作业一个)。。。看一看()@vefthym谢谢你的提示。我会调查的!如果我能做点什么,我会让你知道。这是一个很好的建议,实施起来相当直接。谢谢你,铁匠
    List<String> list = new ArrayList<String>(3);
    for(Text v : values){
        list.add(v.toString());     
    }
    Collections.sort(list);
    
    StringBuilder builder = new StringBuilder();
    for(String s : list){
        builder.append(s.substring(2)+"\t");    
    } 
    
    context.write(key, new Text(builder.toString().trim()));