Q:

Merge tab delimited files by key

I have three MapReduce jobs that produce tab delimited files, that operate on the same files. The first value is the key. This is the case for every output of these three MR jobs.
What I want to do now, is use MapReduce to "stitch" these files together by key. What would be the best Mapper output and Reducer input? I tried using ArrayWritable, but because of the shuffle, for some records the ArrayWritable from 1 file is in the third position, instead of the second.
I want this:
Key \t Values-from-first-MR-job \t Values-from-second-MR-job \t Values-from-third-MR-job

And this should be the same for all records. But, as I said, because of the shuffle, sometimes this happens for a few records:
Key \t Values-from-third-MR-job \t Values-from-first-MR-job \t Values-from-second-MR-job

How should I set up my Mapper and Reducer to fix this?

A:

It's possible with simple tagging on the emitted value since only three types of files are involved. In map extract the path of the split, identify its position and add a suitable prefix to the value. For clarity, say the outputs are in 3 directories :

path1/mr_out_1
path2/mr_out_2
path3/mr_out_3

Using TextInputForamt for all these paths, in map you will do :
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);

If you have all the files in the same directory, use the fileName instead of dirName. Then identify the flag based on the name(a regex match may be suitable)  :
String fileName = filePath.getName().toString();
if(fileName.matches("regex")){ ... } 

In reduce just put the incoming values to a List and sort. Rest is simple enough. 
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()));

I think it will serve the purpose. Keep in mind that the Collection.sort strategy will fail if there are more than 9 files (due to alphabetical order). Then you may extract the tag separately, cast it to an Integer and use a TreeMap<tag, actualString> for sorting. 
NB: All the above snippets are using new API. I didn't use an IDE to write those, so few syntax errors may exist. And again I didn't follow proper conventions in writing. Say the outKey of map could be a class member, and using outKey.set(keyVal[0]) could remove a Text object creation overhead.    

