Spark-为什么在打印RDD之前必须将collect()收集到驱动程序节点?不能并行完成吗?

时间:2018-07-27 18:37:28

标签: java apache-spark parallel-processing rdd

我正在阅读有关如何在Spark中打印RDD(我正在使用Java),并且似乎大多数人只是collect()(如果RDD足够小)并使用forall(println)之类的东西像那样。不能并行打印?为什么我们必须将数据收集到驱动程序节点上才能进行打印?

我当时在想也许是因为我们不能并行使用System.out,但是我觉得不是那样。而且,我不太确定如何使用代码来分发数据并并行打印。我想到的一种方法是做一个mappartitions,它对映射没有任何帮助,但是会遍历该分区并打印其内容。

1 个答案:

答案 0 :(得分:1)

调用collect()方法时,会将所有结果返回到驱动程序节点。您将拥有一个List而不是RDD。让我们看一个在本地模式下的示例。假设您的RDD为Integer:

JavaRDD<Integer> rdd = sc.parallelize(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));

如果调用foreach方法(在Java中为stream().forEach()),驱动程序节点将按照创建它的顺序打印RDD中的所有元素。

rdd.collect().stream().forEach(x -> System.out.println(x));

Output: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

如果要在每个工作程序上打印结果,则必须调用foreach中的RDD方法。它不会返回驱动程序任何内容,只会在每个工作程序节点上执行您在foreach方法中指定的计算。

rdd.foreach(x -> System.out.println(x));

如果您看到控制台(本地模式),您会注意到System.out.println(x)已在单独的线程中执行,因为输出不遵守原始顺序:

Output: 6, 3, 2, 1, 8, 9, 10, 4, 5, 7

因此,如果您以分布式模式执行它,那么每个执行器都会在其日志文件上打印System.out.println操作的结果。

您还提到了mapPartitions方法。对于您而言,我发现它比直接在foreach上使用RDD更有用。这可能有助于控制工人的工作量。

 rdd.repartition(5).mapPartitions(x -> {
     while(x.hasNext()){
         Integer i = x.next();
         System.out.println(i);
     }
     return x;
 }).count(); // Count is just to force the execution of mapPartition (mapPartition is lazy and doesn't get executed until an action is called)

希望有帮助!