如何打印RDD的内容?


124

我正在尝试将集合的内容打印到Spark控制台。

我有一个类型:

linesWithSessionId: org.apache.spark.rdd.RDD[String] = FilteredRDD[3]

我使用命令:

scala> linesWithSessionId.map(line => println(line))

但这是打印:

res1:org.apache.spark.rdd.RDD [Unit] = MappedRDD [4]在地图上的位置:19

如何将RDD写入控制台或将其保存到磁盘,以便查看其内容?


1
嗨!您是否阅读了您接受的答案的评论?它似乎具有误导性
-dk14

2
@ dk14同意,我已经重新分配了接受的答案
蓝天

RDD被降级为二等公民,您应该使用DataFrame和该show方法。
Thomas Decaux

Answers:


235

如果要查看RDD的内容,一种方法是使用collect()

myRDD.collect().foreach(println)

但是,当RDD有数十亿行时,这不是一个好主意。用于take()仅打印一些内容:

myRDD.take(n).foreach(println)

1
如果我在RDD(具有数百万行)上使用foreach将内容作为单个文件写入HDFS,它将在群集上没有任何问题吗?
Shankar

我不在saveAsTextFileRDD上使用的原因是,我需要将RDD内容写入多个文件,这就是为什么我要使用foreach
Shankar 2015年

如果要保存在单个文件中,可以在调用saveAsTextFile之前将RDD合并到一个分区中,但这又可能会引起问题。我认为最好的选择是在HDFS中写入多个文件,然后使用hdfs dfs --getmerge来合并文件
Oussama

您说过,在RDD上使用foreach时,它将永久保存在驱动程序的RAM中,该语句正确吗?因为我理解的是foreach将在每个worker [cluster]而不是驱动程序上运行。
香卡

saveAsTextFile将为每个分区写入一个文件,这就是您想要的文件(多个文件)。否则,如Oussama所建议的那样,您可以执行rdd.coalesce(1).saveAsTextFile()获得一个文件。如果RDD太少分区为自己的喜好,你可以尝试rdd.repartition(N).saveAsTextFile()
雾号

49

map函数是一个转换,这意味着Spark直到您对其执行操作之前不会真正评估您的RDD 。

要打印,可以使用foreach(这是一个操作):

linesWithSessionId.foreach(println)

要将其写入磁盘,您可以使用RDD API中的saveAs...功能之一(静态操作)


6
也许您需要提一下,collect以便可以在控制台中打印RDD。
zsxwing 2014年

1
foreach本身将首先“实现” RDD,然后println在每个元素上运行,因此collect这里并不是真正需要的(尽管您当然可以使用它)...
fedragon 2014年

5
实际上,没有collect(),在foreach之前,我无法在控制台上看到任何内容。
维托里奥·科佐利诺(Fittorio Cozzolino)

3
实际上,即使在1.2.0中,它在我的Spark shell中也可以正常工作。但是我想我知道这种混淆是从哪里来的:最初的问题是询问如何将RDD打印到Spark控制台(= shell),所以我认为他会执行本地作业,在这种情况下foreach可以正常工作。如果要在集群上运行作业,并且要打印rdd,则应该collect(如其他注释和答案所指出的那样)以便在println执行之前将其发送到驱动程序。take如果RDD太大,按照Oussama的建议使用可能是一个好主意。
fedragon 2015年

6
上面的答案是错误的。您不应该接受。Foreach不会打印到控制台,它将打印在您的工作节点上。如果只有一个节点,则foreach将起作用。但是,如果您只有一个节点,那么为什么要使用spark?只需使用SQL awk或Grep或更简单的方法即可。因此,我认为唯一有效的答案是收集。如果收集对您来说很重要,而您只希望使用样品,则可以采用如下所述的取样或头或类似功能。
eshalev

12

如果您在群集上运行此命令,则println不会打印回您的上下文。您需要将RDD数据带入会话。为此,您可以将其强制到本地数组,然后将其打印出来:

linesWithSessionId.toArray().foreach(line => println(line))

12

您可以将其转换RDD为a DataFrame然后将show()其转换为。

// For implicit conversion from RDD to DataFrame
import spark.implicits._

fruits = sc.parallelize([("apple", 1), ("banana", 2), ("orange", 17)])

// convert to DF then show it
fruits.toDF().show()

这将显示数据的前20行,因此数据大小不成问题。

+------+---+                                                                    
|    _1| _2|
+------+---+
| apple|  1|
|banana|  2|
|orange| 17|
+------+---+

1
我认为是import spark.implicits._
Ryan Hartman

这里使用了什么库?我无法检测没有toDF,也没有spark.implicits._火花范围。
Sergii

1

myRDD.foreach(println)和之间可能存在许多架构上的差异myRDD.collect().foreach(println)(不仅是“收集”,还有其他动作)。我看到的区别是这样做的时候myRDD.foreach(println),输出将是随机的。例如:如果我的rdd来自文本文件,其中每一行都有一个数字,则输出将具有不同的顺序。但是当我这样做时myRDD.collect().foreach(println),顺序仍然像文本文件一样。


1

在python中

   linesWithSessionIdCollect = linesWithSessionId.collect()
   linesWithSessionIdCollect

这将打印出RDD的所有内容


1
谢谢,但是我用scala而不是python标记了这个问题
blue-sky

1
c.take(10)

并且Spark新版本会很好地显示表格。


1

您不必每次都键入,而是可以;

[1]在Spark Shell中创建通用打印方法。

def p(rdd: org.apache.spark.rdd.RDD[_]) = rdd.foreach(println)

[2]甚至更好,使用隐式函数,可以将函数添加到RDD类以打印其内容。

implicit class Printer(rdd: org.apache.spark.rdd.RDD[_]) {
    def print = rdd.foreach(println)
}

用法示例:

val rdd = sc.parallelize(List(1,2,3,4)).map(_*2)

p(rdd) // 1
rdd.print // 2

输出:

2
6
4
8

重要

仅当您在本地模式下使用少量数据集时,这才有意义。否则,由于大数据集结果,您将无法在客户端上看到结果或内存不足。



By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.