iterable接口中的hadoop模糊性及其java实现

92vpleto  于 2021-05-31  发布在  Hadoop
关注(0)|答案(1)|浏览(518)

是java吗 Iterator 接口强制我们在调用 next() 此接口上的方法?我浏览了文档,没有义务每次调用都返回一个新对象,但这会导致许多歧义。看起来,hadoopmapreduce框架打破了一些未记录的规则,这在我的简单程序(包括使用java8流)中造成了许多问题。当我调用 next() 上的方法 Iterator (虽然这与我的想象相悖,但似乎并没有违反法律的规定 Iterator ,至少它似乎并没有打破有文件记载的规则 Iterator 接口)。我想知道为什么会这样?是mapreduce故障吗?还是java没有记录的错误 Iterator 接口在每次调用时返回新示例 next() 方法:
为了简单起见,并展示hadoopmapreduce中正在发生的事情,我编写了自己的mapreduce Iterator 这与mapreduce所做的类似,因此您可以理解我的意思(因此它不是一个完美的程序,可能有很多问题,但请关注我试图展示的概念)。假设我有以下 Hospital 实体:

  1. @Getter
  2. @Setter
  3. @AllArgsConstructor
  4. @ToString
  5. public class Hospital {
  6. private AREA area;
  7. private int patients;
  8. public Hospital(AREA area, int patients) {
  9. this.area = area;
  10. this.patients = patients;
  11. }
  12. public Hospital() {
  13. }
  14. }

为此我写了以下文章 MyCustomHospitalIterable :

  1. public class MyCustomHospitalIterable implements Iterable<Hospital> {
  2. private List<Hospital> internalList;
  3. private CustomHospitalIteration customIteration = new CustomHospitalIteration();
  4. public MyCustomHospitalIterable(List<Hospital> internalList) {
  5. this.internalList = internalList;
  6. }
  7. @Override
  8. public Iterator<Hospital> iterator() {
  9. return customIteration;
  10. }
  11. public class CustomHospitalIteration implements Iterator<Hospital> {
  12. private int currentIndex = 0;
  13. private Hospital currentHospital = new Hospital();
  14. @Override
  15. public boolean hasNext() {
  16. if (MyCustomHospitalIterable.this.internalList.size() - 1 > currentIndex) {
  17. currentIndex++;
  18. return true;
  19. }
  20. return false;
  21. }
  22. @Override
  23. public Hospital next() {
  24. Hospital hospital =
  25. MyCustomHospitalIterable.this.internalList.get(currentIndex);
  26. currentHospital.setArea(hospital.getArea());
  27. currentHospital.setPatients(hospital.getPatients());
  28. return currentHospital;
  29. }
  30. }
  31. }

在这里,我不是在next()方法调用时返回新对象,而是返回具有不同内容的相同对象。你可能会问这样做的好处是什么?它在mapreduce中有自己的优势,因为在大数据中,他们不想为了性能考虑而创建新对象。这是否违反了任何记录在案的规则 Iterator 接口?
现在让我们看看实施 Iterable 这样:考虑以下简单程序:

  1. public static void main(String[] args) {
  2. List<Hospital> hospitalArray = Arrays.asList(
  3. new Hospital(AREA.AREA1, 10),
  4. new Hospital(AREA.AREA2, 20),
  5. new Hospital(AREA.AREA3, 30),
  6. new Hospital(AREA.AREA1, 40));
  7. MyCustomHospitalIterable hospitalIterable = new MyCustomHospitalIterable(hospitalArray);
  8. List<Hospital> hospitalList = new LinkedList<>();
  9. Iterator<Hospital> hospitalIter = hospitalIterable.iterator();
  10. while (hospitalIter.hasNext()) {
  11. Hospital hospital = hospitalIter.next();
  12. System.out.println(hospital);
  13. hospitalList.add(hospital);
  14. }
  15. System.out.println("---------------------");
  16. System.out.println(hospitalList);
  17. }

这是如此不合逻辑和违反直觉的程序输出如下:

  1. Hospital{area=AREA2, patients=20}
  2. Hospital{area=AREA3, patients=30}
  3. Hospital{area=AREA1, patients=40}
  4. ---------------------
  5. [Hospital{area=AREA1, patients=40}, Hospital{area=AREA1, patients=40}, Hospital{area=AREA1, patients=40}]

更糟糕的是,想象一下当我们和 Streams 在 java 。以下java程序的输出是什么:

  1. public static void main(String[] args) {
  2. List<Hospital> hospitalArray = Arrays.asList(
  3. new Hospital(AREA.AREA1, 10),
  4. new Hospital(AREA.AREA2, 20),
  5. new Hospital(AREA.AREA3, 30),
  6. new Hospital(AREA.AREA1, 40));
  7. MyCustomHospitalIterable hospitalIterable = new MyCustomHospitalIterable(hospitalArray);
  8. Map<AREA, Integer> sortedHospital =
  9. StreamSupport.stream(hospitalIterable.spliterator(), false)
  10. .collect(Collectors.groupingBy(
  11. Hospital::getArea, Collectors.summingInt(Hospital::getPatients)));
  12. System.out.println(sortedHospital);
  13. }

这取决于我们使用并行流还是顺序流:在sequential中,一个输出如下:

  1. {AREA2=20, AREA1=40, AREA3=30}

与之平行的是:

  1. {AREA1=120}

作为一个用户,我想按他们的原样使用这个接口,而不关心这个接口的实现。
问题是我知道怎么做 MyCustomHospitalIterable 但在hadoopmapreduce中,我必须实现像bellow这样的方法,我不知道在哪里 Iterable<IntWritable> 从何而来,又是如何实施的。我只想把它当作一个纯粹的 Iterable 但正如我在上面所展示的,它并没有像预期的那样工作:

  1. public void reduce(Text key, Iterable<IntWritable> values, Context context
  2. ) throws IOException, InterruptedException {
  3. List<IntWritable> list = new LinkedList<>();
  4. Iterator<IntWritable> iter = values.iterator();
  5. while (iter.hasNext()) {
  6. IntWritable count = iter.next();
  7. System.out.println(count);
  8. list.add(count);
  9. }
  10. System.out.println("---------------------");
  11. System.out.println(list);
  12. }

我的问题是:为什么我的简单程序坏了?
不执行不可推卸的常规规则是不是错了 Iterable 以及 Iterator (或者有我没有注意到的关于这种行为的文档)?
还是因为java没有文档化 Iterable 以及 Iterator 接口在每次调用时返回新对象?
还是因为我是个程序员?

oipij1gg

oipij1gg1#

对于iterable,返回相同的可变对象和不同的内容是非常不寻常的。我在java语言参考中没有找到什么东西;虽然搜索不多。它太简单,太容易出错,不利于正确的语言使用。
你提到的其他工具,比如streams,也很贴切。
另外,下一个java的记录类型只是用于类似元组的用法,当然是作为多个不可变对象。”您的“iterable”无法在集合中使用,除非在 .next().clone() 或者类似的。
iterable的这一缺点与将可变对象作为Map键属于同一类。这是大错特错。

相关问题