我正在阅读有关如何在Spark中打印RDD(我正在使用Java),并且似乎大多数人只是collect()
(如果RDD足够小)并使用forall(println)之类的东西像那样。不能并行打印?为什么我们必须将数据收集到驱动程序节点上才能进行打印?
我当时在想也许是因为我们不能并行使用System.out,但是我觉得不是那样。而且,我不太确定如何使用代码来分发数据并并行打印。我想到的一种方法是做一个mappartitions,它对映射没有任何帮助,但是会遍历该分区并打印其内容。
答案 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)
希望有帮助!