First you'll need a composite writable for all three of your values.
public class CompositeWritable implements Writable {
int val1 = 0;
float val2 = 0;
String val3 = "";
public CompositeWritable() {}
public CompositeWritable(int val1, float val2, String val3) {
this.val1 = val1;
this.val2 = val2;
this.val3 = val3;
}
@Override
public void readFields(DataInput in) throws IOException {
val1 = in.readInt();
val2 = in.readFloat();
val3 = WritableUtils.readString(in);
}
@Override
public void write(DataOutput out) throws IOException {
out.writeInt(val1);
out.writeFloat(val2);
WritableUtils.writeString(out, val3);
}
public void merge(CompositeWritable other) {
this.val1 += other.val1;
this.val2 += other.val2;
this.val3 += other.val3;
}
@Override
public String toString() {
return this.val1 + "\t" + this.val2 + "\t" + this.val3;
}
}
Then in your reduce you'll do something like this...
public void reduce(Text key, Iterable<CompositeWritable> values, Context ctx) throws IOException, InterruptedException{
CompositeWritable out;
for (CompositeWritable next : values)
{
out.merge(next);
}
ctx.write(key, out);
}
Your mapper will simply output one CompositeWritable
per map.
I haven't tried to compile this, but the general idea is there.