Java 使用mapreduce的Hadoop facebook好友

Java 使用mapreduce的Hadoop facebook好友,java,json,hadoop,mapreduce,Java,Json,Hadoop,Mapreduce,我在hadoop(Java版本)中尝试一个mapreduce程序,从json文件中查找共同的朋友列表。json文件内容具有以下模式: {"name":"abc","id":123} [{"name":"xyz","id":124},{"name":"def","id":125},{"name":"cxf","id":155}] {"name":"cxf","id":155} [{"name":"xyz","id":124},{"name":"abc","id":123},{"name":"yyy

我在hadoop(Java版本)中尝试一个mapreduce程序,从json文件中查找共同的朋友列表。json文件内容具有以下模式:

{"name":"abc","id":123} [{"name":"xyz","id":124},{"name":"def","id":125},{"name":"cxf","id":155}]
{"name":"cxf","id":155} [{"name":"xyz","id":124},{"name":"abc","id":123},{"name":"yyy","id":129}]
模式解释如下:

好友json选项卡,由相关好友json数组分隔

因此abc将xyz、def和cxf作为朋友 cxf将xyz abc和yyy作为朋友

鉴于上述情况,abc和cxf之间的共同朋友是xyz

尝试使用mapreduce通过创建自定义可写项来实现同样的功能,映射器会发出以下键值,键值为好友对,值为键值中第一个好友(即好友对)的相关好友

这里的键实际上是一个自定义的可写的,创建了一个扩展了WritableComparable的类,我已经重写了compareTo方法,这样这两个对(a,b)和(b,a)都是相同的。但我面临的问题是,compareTo方法并不是对所有对的组合都调用的,因此reducer逻辑失败了

基于上述示例,映射器发射了6个K,V对。但是compareTo只被调用了5次,分别是key1.compareTo(key2)、key2.compareTo(key3)、key3.compareTo(key4)、key4.compareTo(key5)、key5.compareTo(key6)

知道为什么会这样吗

以下是f11ler建议的逻辑代码

驱动程序类别:

package com.facebook.updated;

import java.io.IOException;

import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.SequenceFileOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
import org.apache.log4j.Logger;

public class FacebookMain extends Configured implements Tool

{

    Logger logger = Logger.getLogger(FacebookMain.class);

    public static void main(String[] args) throws Exception {
        System.exit(ToolRunner.run(new FacebookMain(), args));

    }

    @Override
    public int run(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        logger.info("Running======>");
        Job job = Job.getInstance();

        job.setJarByClass(FacebookMain.class);
        job.setJobName("FBApp");

        job.setMapOutputKeyClass(Friend.class);
        job.setMapOutputValueClass(Friend.class);

        job.setOutputKeyClass(FriendPair.class);
        job.setOutputValueClass(Friend.class);

        job.setMapperClass(FacebookMapper.class);
        job.setReducerClass(FacebookReducer.class);

        job.setInputFormatClass(org.apache.hadoop.mapreduce.lib.input.TextInputFormat.class);
        job.setOutputFormatClass(SequenceFileOutputFormat.class);

        FileInputFormat.setInputPaths(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));

        boolean val = job.waitForCompletion(true);

        return val ? 0 : 1;

    }

}
自定义可写项(用于表示朋友和朋友对)

减速器的输出
(abc,abc)->xyz

比较排序需要使用方法,此关系应该是可传递的。这意味着如果a>b和b>c,那么a>c。对于您的实现来说,这可能不是真的

为什么要在mapper中生成此类记录? 如果“成为朋友”是一种对称关系,您只需使用此逻辑(伪代码)执行仅映射器的工作即可:

Mapreduce将按键对该值进行分组,因此reducer的输入:

xyz -> [abc,cxf]
def -> [abc]
cxf -> [abc]
abc -> [cxf]
yyy -> [cxf]
在reducer中,我们按值进行嵌套循环,但跳过与self的比较。结果:

(abc, cxf) -> xyz

这就是我们想要得到的。

这是不可能的,因为在hadoop中,mapper一次读取一行,并且无法在一次运行Mappera时以编程方式查看两对是否匹配。此外,记录可能以不同的输入拆分形式出现,即。,由不同的映射程序处理。您的输入文件是否包含如下字符串:
{“name”:“abc”,“id”:123}[{“name”:“xyz”,“id”:124},{“name”:“def”,“id”:125},{“name”:“cxf”,“id”:123}]
?这意味着
xyz
def
有共同的朋友
abc
xyz
cxf
有共同的朋友
abc
,依此类推。。。这就是您不需要匹配不同记录的原因。文件中的一行如下所示:{“name”:“abc”,“id”:123}[{“name”:“xyz”,“id”:124},{“name”:“def”,“id”:125},{“name”:“cx”‌​这意味着abc有朋友xyz、def和cxf另一行类似于{“名称”:“cxf”、“id”:123}[{“名称”:“xyz”、“id”:124},{“名称”:“abc”、“id”:123},{“名称”:“yyy”、“id”:129}],这意味着cxf有朋友abc、xyz和yyy。鉴于这两条线(abc、cxf),xyz是双方的朋友。这就是我在输出中需要的。这就是为什么我需要Hadoop考虑(ABC,CXF)和(CXF,ABC)的原因,这就是为什么我写“如果”是一个朋友“是一个对称关系”。我更新了我的答案。尝试搜索块嵌套循环joinsAm的逻辑。我不确定我是否理解这意味着什么。你能解释一下块嵌套循环联接吗?我建议你阅读什么是块嵌套循环联接,以防你发现它们有用。实际上,您需要将每一行与每一行进行比较(即使它存在于不同的输入分割中)。例如,看一看本文的第3节:参考pdf,发现它相当复杂,但了解到这一点,块连接嵌套循环允许您在不进行M*N迭代的情况下有效地将一个集合的记录与另一个集合的记录进行比较。对(abc,cxf)和(cxf,abc)不调用compareTo方法,因此将它们视为两个不同的键OK,您不必遵循这种方法,我只是认为了解它在您的情况下可能会很有用。祝你好运
package com.facebook.updated;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.log4j.Logger;

import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.util.JSON;

public class FacebookMapper extends Mapper<LongWritable, Text, Friend, Friend> {

    Logger log = Logger.getLogger(FacebookMapper.class);

    @Override
    protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Friend, Friend>.Context context)
            throws IOException, InterruptedException {

        String line = value.toString();
        StringTokenizer st = new StringTokenizer(line, "\t");
        String person = st.nextToken();
        String friends = st.nextToken();

        BasicDBObject personObj = (BasicDBObject) JSON.parse(person);
        BasicDBList friendsList = (BasicDBList) JSON.parse(friends);

        List<Friend> frndJavaList = new ArrayList<>();

        for (Object frndObj : friendsList) {
            frndJavaList.add(getFriend((BasicDBObject) frndObj));
        }

        Friend frnd = getFriend(personObj);
        Friend[] array = frndJavaList.toArray(new Friend[frndJavaList.size()]);
        for (Friend f : array) {
            log.info("Map output is " + f + " and " + frnd);
            context.write(f, frnd);
        }
    }

    private static Friend getFriend(BasicDBObject personObj) {
        Friend frnd = new Friend();
        frnd.setId(new IntWritable(personObj.getInt("id")));
        frnd.setName(new Text(personObj.getString("name")));
        frnd.setHomeTown(new Text(personObj.getString("homeTown")));
        return frnd;
    }
}

package com.facebook.updated;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.hadoop.mapreduce.Reducer;
import org.apache.log4j.Logger;

public class FacebookReducer extends Reducer<Friend, Friend, FriendPair, Friend> {

    Logger log = Logger.getLogger(FacebookReducer.class);

    @Override
    protected void reduce(Friend friend, Iterable<Friend> vals,
            Reducer<Friend, Friend, FriendPair, Friend>.Context context) throws IOException, InterruptedException {
        List<Friend> friends = new ArrayList<>();
        for (Friend frnd : vals) {
            friends.add(frnd);
        }
        log.info("Reducer output is " + friend + " and values are " + friends);
        if (friends.size() == 2) {
            FriendPair key = new FriendPair(friends.get(0), friends.get(1));
            context.write(key, friend);
        } else {
            //log.info("Size of friends is not 2 key is " + friend + " and values are " + friends);
        }

    }
}
{"name":"abc","id":123} [{"name":"xyz","id":124},{"name":"def","id":125},{"name":"cxf","id":155}]
{"name":"cxf","id":155} [{"name":"xyz","id":124},{"name":"abc","id":123},{"name":"yyy","id":129}]
for(int i = 0; i < values.length; ++i)
    for(int j = 0; j < values.length; ++j)
        if (i ==j)
            continue
        emmit (values[i], values[j]), key
for(int i = 0; i < values.length; ++i)
    emmit values[i], key
for(int i = 0; i < values.length; ++i)
    for(int j = 0; j < values.length; ++j)
        if (i ==j)
            continue
        emmit (values[i], values[j]), key
xyz -> abc
def -> abc
cxf -> abc
xyz -> cxf
abc -> cxf
yyy -> cxf
xyz -> [abc,cxf]
def -> [abc]
cxf -> [abc]
abc -> [cxf]
yyy -> [cxf]
(abc, cxf) -> xyz