关于mapreduce中的倒排索引例题以及StringBuilder的注意事项

今天学习了mapreduce中的倒排索引,遇到一个求微博共同关注的题目:
周杰伦:科比,蔡依林,林书豪,林俊杰
姚明:林书豪,詹姆斯,哈登,蔡依林
蔡依林:林俊杰,周杰伦,大S,林书豪
林书豪:詹姆斯,科比,保罗,艾弗森

上述数据格式为:
账号:关注的人

需求:
现在找出哪些人 两两之间有共同关注的人,以及共同关注的人都有谁?

想得到这样的一个结果:
(周杰伦-蔡依林,{林俊杰,林书豪})

**

解题思路:

**
1.根据mapreduce中shuffle阶段根据相同key分组的思想,通过第一个mapreduce求出被关注人的数组

关于mapreduce中的倒排索引例题以及StringBuilder的注意事项
2.再通过第二个mapreduce,对数据进行处理,最终得出我们想要的结果关于mapreduce中的倒排索引例题以及StringBuilder的注意事项

做题的过程中,思路是比较清晰的,附上代码:

第一个map:

public class ConcernMapper1 extends Mapper<LongWritable, Text, Text, Text> {

Text k = new Text();

@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {

    //1、利用mapreduce会对相同key进行分组的特点,将被  <被关注者,关注者>输出到reduce端
    String[] line = value.toString().split(":");
    String concernPeoson = line[0];//关注者

    String[] names = line[1].split(",");//关注的人

    for (String str : names) {

        k.set(str);

        /*
        * 输出数据:
        * 林书豪 姚明
        * 林书豪 蔡依林
        * 林书豪 周杰伦
        *
        *
        * 经过shuffle阶段到reduce时,数据变成了
        *
        *  林书豪  {姚明 蔡依林 周杰伦}
        *
        *
        *
        *
        * */

        context.write(k, new Text(concernPeoson));
    }

}

}

第一个reduce:
public class ConcerReduce1 extends Reducer<Text, Text, Text, Text> {

Text k = new Text();
StringBuilder sb = new StringBuilder();

@Override
protected void reduce(Text key, Iterable<Text> values, Context context)
        throws IOException, InterruptedException {



    for (Text concerned : values) {

        sb.append(concerned.toString()).append(",");

    }

    k.set(sb.toString());
    context.write(key, k);


}

}

第二个map:

public class ConcernMapper2 extends Mapper<LongWritable,Text,Text,Text> {

String name = "";


@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
    String[] split = value.toString().split("\t");

    String concernedPeoson = split[0];//被关注的人

    //对关注人的数组进行排序,防止出现  周杰伦-姚明 与 姚明-周杰伦,被reduce认为时不同的key,从而但不到需求
    String[] concernPeople = split[1].split(",");//关注者

    Arrays.sort(concernPeople);

    //将排序后的[周杰伦,姚明,蔡依林]数组 [蔡依林,姚明,周杰伦] 以 周杰伦-姚明 周杰伦-蔡依林的形式输出




    for (int i = 0;i<concernPeople.length-1;i++){

           for (int j = 1 ;j<concernPeople.length;j++) {

               name =concernPeople[i] + "-" + concernPeople[j];


               context.write(new Text(name), new Text(concernedPeoson));

           }

    }


}

}

第二个reduce:
public class ConcernReduce2 extends Reducer<Text,Text,Text,Text> {

StringBuilder stringBuilder = new StringBuilder();



@Override
protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {

    for (Text concerned : values){

        stringBuilder.append(concerned.toString()).append(" ");

    }

    context.write(key,new Text(stringBuilder.toString()) );


}

}

但是碰到了一个没有注意到的问题,导致输出的结果不符合要求,以下是运行第一个mapreduceDriver后的结果:
关于mapreduce中的倒排索引例题以及StringBuilder的注意事项
运行第二个driver后的结果:
关于mapreduce中的倒排索引例题以及StringBuilder的注意事项

输出的结果差强人意,十分的杂乱

回头看了下代码,最终发现问题是将StringBuilder sb = new StringBuilder();写在reduce方法外,导致sb这个实例一致存在,且不断添加字符。
关于mapreduce中的倒排索引例题以及StringBuilder的注意事项
关于mapreduce中的倒排索引例题以及StringBuilder的注意事项

解决办法: 将StringBuilder sb = new StringBuilder();写在reduce方法内部

关于mapreduce中的倒排索引例题以及StringBuilder的注意事项

输出正常,问题解决
关于mapreduce中的倒排索引例题以及StringBuilder的注意事项