【问题标题】:Hadoop Iterator skip method call at first iterationHadoop Iterator 在第一次迭代时跳过方法调用
【发布时间】:2017-06-13 20:21:01
【问题描述】:

我有一个 Map Reduce 程序,并且在 Reducer 类中我的方法在第一次迭代中没有被调用。我想要实现的是在迭代器的每 2 个连续值之间生成一些新行。 (对,如:(1,2),(2,3),(3,4)...)。我错过了什么?而且我还测试了我有我需要的对,它看起来不错,但似乎我的方法没有为第一对调用.. generate() - 将在每 2 个连续行之间生成新行(填补时间间隙)

input: X, Y, 00:00:00, 908 X, Y, 00:00:05, 122 X, Y, 00:00:07, 123

desired output: X, Y, 00:00:00, 908 X, Y, 00:00:01, 908 X, Y, 00:00:02, 908 X, Y, 00:00:03, 908 X, Y, 00:00:04, 908 X, Y, 00:00:05, 122 X, Y, 00:00:06, 122 X, Y, 00:00:07, 123

Iterator<MyType> iterator = values.iterator();
if (!iterator.hasNext()) return;
first = iterator.next();
while (iterator.hasNext()) {
   nr++;
   first.setStatus(nr);
   context.write(nullWritable, first);
   second = iterator.next();
   List<MyType> newValues = generate(first, second, context);
   for (MyType mt : newValues) {
          mt.setStatus(nr);
          context.write(nullWritable, mt);
    }
   second.setStatus(nr);
   context.write(nullWritable, second);
   first = new InterpolationModelWritable();
   first.setX(second.getX());
   first.setY(second.getY());
   first.setZ(second.getZ());
   first.setTag(second.getTag());

 }

actual result: X, Y, 00:00:00, 908 X, Y, 00:00:05, 122 X, Y, 00:00:06, 122 X, Y, 00:00:07, 123

【问题讨论】:

  • 你能扩展你的问题吗,真的不清楚你的目标是什么,问题是什么。如果我想测试您的代码,是否可以根据您提供的内容进行测试?我需要示例输入、输出和您的预期输出。你调用了generate 方法,它有什么作用?
  • @Binary Nerd 你现在可以看到我的更新了
  • 能否为您的 generate 方法添加逻辑。
  • 恐怕我做不到。但它适用于其他输入行。

标签: java hadoop mapreduce iterator


【解决方案1】:

您的代码的问题在于您陷入了 hadoop 对象重用陷阱。需要记住的重要一点是,reduce 中的值迭代器不会在您每次调用 next() 时返回一个新对象,而是重用同一个对象。

现在我们知道我们可以查看您的代码并找出问题所在。使用您的逻辑(但作为一个最小的工作示例),我们可以看到通常它会起作用。

@Test
public void noResuseIteratorTest() {

    List<String> values = new ArrayList<>();
    values.add("a");
    values.add("b");
    values.add("c");
    values.add("d");

    String first;
    String second;

    Iterator<String> iterator = values.iterator();
    if (!iterator.hasNext()) return;
    first = iterator.next();
    while (iterator.hasNext()) {
        second = iterator.next();
        System.out.println("Out: " + first + " - " + second);
        first = second;
    }
}

输出:a - b
输出:b - c
输出:c - d

但是,在 hadoop reduce 方法中,返回的值是同一个对象。这个测试证明了这个问题:

@Test
public void reuseIteratorTest() {

    class MyList implements Iterable<Text> {

        private List<String> myList = new ArrayList<>();
        private Text reused = new Text();

        public MyList() {
            myList.add("a");
            myList.add("b");
            myList.add("c");
            myList.add("d");
        }

        @Override
        public Iterator<Text> iterator() {
            return new Iterator<Text> () {

                private final Iterator<String> iter = myList.iterator();

                @Override
                public boolean hasNext() {
                    return iter.hasNext();
                }

                @Override
                public Text next() {
                    // We reuse the Text object here!
                    reused.set(iter.next());
                    return reused;
                }

                @Override
                public void remove() {
                    throw new UnsupportedOperationException("");
                }
            };
        }
    }

    MyList myList = new MyList();
    Text first;
    Text second;

    Iterator<Text> iterator = myList.iterator();
    if (!iterator.hasNext()) return;
    first = iterator.next();
    while (iterator.hasNext()) {
        second = iterator.next();
        System.out.println("Out: " + first + " - " + second);
        first = new Text();
        first.set(second);
    }
}

输出:b - b
输出:b - c
输出:c - d

所以,仅仅做second = iterator.next(); 是不够的。在您的第一次迭代中,firstsecond 都指向同一个对象。

要解决这个问题,您需要将迭代器值的内容复制到您的对象中,而不仅仅是指向同一个对象。以 Text 对象为例,固定版本如下所示:

@Test
public void reuseFixedIteratorTest() {

    // MyList class from above goes here

    MyList myList = new MyList();
    Text first = new Text();
    Text second = new Text();

    Iterator<Text> iterator = myList.iterator();
    if (!iterator.hasNext()) return;
    first.set(iterator.next());
    while (iterator.hasNext()) {
        second.set(iterator.next());
        System.out.println("Out: " + first + " - " + second);
        first.set(second);
    }
}

输出:a - b
输出:b - c
输出:c - d

【讨论】:

  • 拯救我的一周!谢谢! @二进制书呆子
猜你喜欢
  • 2013-10-03
  • 2011-08-08
  • 2021-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-15
  • 2019-02-14
  • 1970-01-01
相关资源
最近更新 更多