java—在mapreduce中使用列表作为值返回相同的值

z31licg0  于 2021-05-30  发布在  Hadoop
关注(0)|答案(1)|浏览(357)

我有一个mapreduce作业,它输出一个intwritable作为键,点(我创建的实现可写的对象)作为map函数的值。然后在reduce函数中,我使用for each循环遍历点的iterable来创建一个列表:

@Override
public void reduce(IntWritable key, Iterable<Point> points, Context context) throws IOException, InterruptedException {

    List<Point> pointList = new ArrayList<>();
    for (Point point : points) {
        pointList.add(point);
    }
    context.write(key, pointList);
}

问题是这个列表的大小是正确的,但是每个点都是完全相同的。我的point类中的字段不是静态的,我已经在循环中单独打印了每个点,以确保这些点是唯一的(它们是唯一的)。此外,我还创建了一个单独的类,它只创建几个点并将它们添加到列表中,这似乎是可行的,这意味着mapreduce做了一些我不知道的事情。
任何帮助解决这一点将不胜感激。
更新:Map器类的代码:

private final static IntWritable one = new IntWritable(1);
private Text word = new Text();
private IntWritable firstChar = new IntWritable();
private Point point = new Point();

@Override
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
    String line = value.toString();
    StringTokenizer tokenizer = new StringTokenizer(line, " ");

    while(tokenizer.hasMoreTokens()) {
        String atts = tokenizer.nextToken();
        String cut = atts.substring(1, atts.length() - 1);
        String[] nums = cut.split(",");

        point.set(Double.parseDouble(nums[0]), Double.parseDouble(nums[1]), Double.parseDouble(nums[2]), Double.parseDouble(nums[3]));
        context.write(one, point);
    }
}

点类:

public class Point implements Writable {

public Double att1;
public Double att2;
public Double att3;
public Double att4;

public Point() {

}

public void set(Double att1, Double att2, Double att3, Double att4) {
    this.att1 = att1;
    this.att2 = att2;
    this.att3 = att3;
    this.att4 = att4;
}

@Override
public void write(DataOutput dataOutput) throws IOException {
    dataOutput.writeDouble(att1);
    dataOutput.writeDouble(att2);
    dataOutput.writeDouble(att3);
    dataOutput.writeDouble(att4);
}

@Override
public void readFields(DataInput dataInput) throws IOException {
    this.att1 = dataInput.readDouble();
    this.att2 = dataInput.readDouble();
    this.att3 = dataInput.readDouble();
    this.att4 = dataInput.readDouble();
}

@Override
public String toString() {
    String output = "{" + att1 + ", " + att2 + ", " + att3 + ", " + att4 + "}";
    return output;
}
sz81bmfz

sz81bmfz1#

问题出在你的减速机上。你不想把所有的点都存储在内存中。它们可能很大,hadoop为您解决了这个问题(即使是以一种尴尬的方式)。
当循环通过给定的 Iterable<Points> ,每个 Point 示例被重用,所以它在给定的时间只保留一个示例。
也就是说当你打电话的时候 points.next() ,这两件事将会发生: Point 示例被重用,并与下一个点数据一起设置
同样适用于 Key 示例。
在您的例子中,您将在列表中找到 Point 多次插入并使用上次 Point .
您不应该保存 Writables 或者应该克隆它们。
你可以在这里阅读更多关于这个问题的内容
https://cornercases.wordpress.com/2011/08/18/hadoop-object-reuse-pitfall-all-my-reducer-values-are-the-same/

相关问题