package hip.ch7.friendsofafriend;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
public final class CalcMapReduce {
public static class TextPair extends Text {
public static char separator = '\t';
public TextPair() {
super();
}
public TextPair(String person1, String person2) {
super(joinPersonsLexicographically(person1, person2));
}
public void set(String person1, String person2) {
super.set(joinPersonsLexicographically(person1, person2));
}
public static String joinPersonsLexicographically(String person1,
String person2) {
if (person1.compareTo(person2) < 0) {
return person1 + separator + person2;
}
return person2 + separator + person1;
}
}
public static class Map
extends Mapper<Text, Text, TextPair, IntWritable> {
private TextPair pair = new TextPair();
private IntWritable one = new IntWritable(1);
private IntWritable two = new IntWritable(2);
@Override
protected void map(Text key, Text value, Context context)
throws IOException, InterruptedException {
String[] friends = StringUtils.split(value.toString());
for (int i = 0; i < friends.length; i++) {
// they already know each other, so emit the pair with
// a "1" to indicate this
//
pair.set(key.toString(), friends[i]);
context.write(pair, one);
// go through all the remaining friends in the list
// and emit the fact that they are 2nd-degree friends
//
for (int j = i + 1; j < friends.length; j++) {
pair.set(friends[i], friends[j]);
context.write(pair, two);
}
}
}
}
public static class Reduce
extends Reducer<TextPair, IntWritable, TextPair, IntWritable> {
private IntWritable friendsInCommon = new IntWritable();
@Override
public void reduce(TextPair key, Iterable<IntWritable> values,
Context context)
throws IOException, InterruptedException {
int commonFriends = 0;
boolean alreadyFriends = false;
// if the friends know each other then we'll eventually
// see a value will be a "1", which will cause us to
// break out of the loop
//
for (IntWritable hops : values) {
if (hops.get() == 1) {
alreadyFriends = true;
break;
}
commonFriends++;
}
if (!alreadyFriends) {
friendsInCommon.set(commonFriends);
context.write(key, friendsInCommon);
}
}
}
}