Java 通过for循环在MapReduce中发出中间键-我是否误解了MapReduce?包括基本示例。

Java 通过for循环在MapReduce中发出中间键-我是否误解了MapReduce?包括基本示例。,java,hadoop,mapreduce,Java,Hadoop,Mapreduce,因此,我有一组电子邮件,我想用它们输出唯一的三元组(发件人电子邮件、收件人电子邮件、时间戳),如下所示: user1@stackoverflow.com user2@stackoverflow.com 09/12/2009 16:45 user1@stackoverflow.com user9@stackoverflow.com 09/12/2009 18:45 user3@stackoverflow.com user4@stackoverflow.com 0

因此,我有一组电子邮件,我想用它们输出唯一的三元组(发件人电子邮件、收件人电子邮件、时间戳),如下所示:

user1@stackoverflow.com    user2@stackoverflow.com    09/12/2009 16:45
user1@stackoverflow.com    user9@stackoverflow.com    09/12/2009 18:45
user3@stackoverflow.com    user4@stackoverflow.com    07/05/2008 12:29
在上面的示例中,用户1向多个收件人(用户2和用户9)发送了一封电子邮件。为了存储收件人,我创建了一个数据结构
edgewriteable
(实现
writeablecomparable)
,它将保存发件人收件人电子邮件地址以及时间戳

我的映射器如下所示:

private final EdgeWritable edge = new EdgeWritable(); // Data structure for triplets.
private final NullWritable noval = NullWritable.get(); 

...

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

    byte[] bytes = value.getBytes();
    Scanner scanner = new Scanner(new ByteArrayInputStream(bytes), "UTF-8");
    String from = null; // Sender's Email address
    ArrayList<String> recipients = new ArrayList<String>(); // List of recipients' Email addresses  
    long millis = -1; // Date

    // Parse information from file
    while(scanner.hasNext()) {
        String line = scanner.nextLine();
        if (line.startsWith("From:")) {
            from = procFrom(stripCommand(line, "From:")); // Get sender e-mail address.
        } else if (line.startsWith("To:")) {
            procRecipients(stripCommand(line, "To:"), recipients); // Populate recipients into a list. 
        } else if (line.startsWith("Date:")) {
            millis = procDate(stripCommand(line, "Date:")); // Get timestamp.

        if (line.equals("")) { // Empty line indicates the end of the header
            break;
        }
    }
    scanner.close();

    // Emit EdgeWritable as intermediate key containing Sender, Recipient and Timestamp. 
    if (from != null && recipients.size() > 0 && millis != -1) { 
        //EdgeWritable has 2 Text values (ew[0] and ew[1]) and a Timestamp. ew[0] is the sender, ew[1] is a recipient.
        edge.set(0, from); // Set ew[0]  
        for(int i = 0; i < recipients.size(); i++) {
            edge.set(1, recipients.get(i)); // Set edge from sender to each recipient i. 
            edge.setTS(millis); // Set date. 
            context.write(edge, noval); // Emit the edge as an intermediate key with a null value. 
        }
    }
}

...
private final edgewriteable edge=新edgewriteable();//三胞胎的数据结构。
private final nullwriteable noval=nullwriteable.get();
...
@凌驾
公共无效映射(文本键、字节可写值、上下文)
抛出IOException、InterruptedException{
byte[]bytes=value.getBytes();
Scanner Scanner=新的扫描器(新的ByteArrayInputStream(字节),“UTF-8”);
String from=null;//发件人的电子邮件地址
ArrayList recipients=新建ArrayList();//收件人电子邮件地址列表
长毫秒=-1;//日期
//解析文件中的信息
while(scanner.hasNext()){
字符串行=scanner.nextLine();
if(第行startsWith(“From:”){
from=procFrom(stripCommand(第行,“from:”);//获取发件人电子邮件地址。
}else if(第行startsWith(“To:”){
procRecipients(stripCommand(第行,“To:”),recipients);//将收件人填充到列表中。
}else if(第行startsWith(“日期:”){
millis=procDate(stripCommand(第行,“日期:”);//获取时间戳。
if(line.equals(“”){//空行表示标头的结尾
打破
}
}
scanner.close();
//发出EdgeWritable作为包含发件人、收件人和时间戳的中间密钥。
如果(from!=null&&recipients.size()>0&&millis!=-1){
//EdgeWritable有2个文本值(ew[0]和ew[1])和一个时间戳。ew[0]是发送方,ew[1]是接收方。
edge.set(0,from);//set ew[0]
对于(int i=0;i
My reducer仅格式化日期并输出边缘:

public void reduce(EdgeWritable key, Iterable<NullWritable> values, Context context) throws IOException, InterruptedException {
    String date = MailReader.sdf.format(edge.getTS());
    out.set(edge.get(0) + " " + edge.get(1) + " " + date); // same edge from Mapper (an EdgeWritable). 
    context.write(noval, out); // same noval from Mapper (a NullWritable).
}
public void reduce(EdgeWritable键、Iterable值、上下文上下文)抛出IOException、InterruptedException{
String date=MailReader.sdf.format(edge.getTS());
out.set(edge.get(0)+“”+edge.get(1)+“”+date);//映射程序中的同一条边(可写的边)。
write(noval,out);//映射器中的相同noval(可空写)。
}
使用EdgeWritable作为中间键,使用NullWritable作为值(在映射器中)这是我的第一个Hadoop/MapReduce程序,我只是想知道我走的方向是正确的。我在网上看过很多MapReduce示例,从来没有见过像我这样在for循环中发出键/值对。我觉得我缺少了某种trick,但以这种方式使用for循环是我能想到的唯一方法


这是“坏”吗?我希望这是清楚的,但是如果需要进一步的澄清,请告诉我。

为每个记录调用Map方法,因此您的数组列表对于每个调用只有一个记录。在类级别声明您的数组列表,以便您可以存储所有记录的值。然后在clean-up方法中,您可以执行您已经编写了内部映射。请尝试此方法,并让我知道它是否有效。

将为每个记录调用映射方法,因此您的数组列表对于每个调用只有一条记录。请在类级别声明数组列表,以便您可以存储所有记录的值。然后在清理方法中,您可以执行在映射中编写的发射逻辑。请尝试是的,让我知道这是否有效。

我必须说,就目前情况而言,该程序是有效的。它以我希望的方式输出电子邮件。我只是想知道使用for循环来发出这样的边是“欺骗”还是被视为不好的做法。我从未在MapReduce示例中见过它。你认为如何?在循环中发出它们没有错。你可以从你的map方法中发出多个值。我必须说,实际上,这个程序是工作的。它以我想要的方式输出电子邮件。我只是想知道使用for循环发出这样的边是“欺骗”还是被视为不好的做法。我从来没有在MapReduce示例中见过它。你认为呢?emi没有错在循环中设置它们。您可以从map方法中发出多个值。