Як надрукувати вміст 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 погодився, я переписав прийняту відповідь
blue-sky

RDD відмовляються як громадяни другого класу, ви повинні використовувати DataFrame та showметод.
Томас Деко

Відповіді:


235

Якщо ви хочете переглянути вміст RDD, одним із способів є використання collect():

myRDD.collect().foreach(println)

Але це не дуже гарна ідея, коли RDD має мільярди рядків. Використовуйте take()для того, щоб роздрукувати лише декілька:

myRDD.take(n).foreach(println)

1
якщо я використовую foreach на RDD (який має мільйони рядків), щоб записати вміст у HDFS як єдиний файл, чи буде він працювати без проблем на кластері?
Шанкар

Причиною, яку я не використовую saveAsTextFileв RDD, є те, що мені потрібно записати вміст RDD у більше ніж один файл, ось чому я використовуюforeach
Shankar

Якщо ви хочете зберегти в одному файлі, ви можете об'єднати RDD в один розділ перед тим, як викликати saveAsTextFile, але це знову ж може спричинити проблеми. Я думаю, що найкращим варіантом є записування декількох файлів у HDFS, а потім використовувати hdfs dfs --getmerge для об’єднання файлів
Oussama

Ви сказали, що якщо використовувати foreach на RDD, він збереже його в оперативній пам’яті водія, чи твердження правильне? тому що, що я зрозумів, це foreach буде працювати на кожного працівника [кластера], а не на драйвері.
Шанкар

saveAsTextFile запише один файл на розділ, що саме вам потрібно (кілька файлів). Інакше, як пропонує Oussama, ви можете зробити rdd.coalesce (1) .saveAsTextFile (), щоб отримати один файл. Якщо у RDD є занадто мало розділів на ваш смак, ви можете спробувати rdd.repartition (N) .saveAsTextFile ()
foghorn

49

mapФункція є перетворенням , а це значить , що іскра НЕ буде на самому ділі оцінити вашу RDD , поки ви не запустите дію на нього.

Щоб роздрукувати його, ви можете використовувати foreach(що є дією):

linesWithSessionId.foreach(println)

Щоб записати його на диск, ви можете скористатися однією з saveAs...функцій (нерухомих дій) API RDD


6
Можливо, вам потрібно згадати, collectщоб RDD можна було надрукувати в консолі.
zsxwing

1
foreachсам спочатку "матеріалізує" RDD, а потім запустить printlnкожен елемент, тому collectтут насправді не потрібно (хоча ви, звичайно, можете використовувати його) ...
fedragon

5
Насправді без збирання (), перш ніж передбачити, я не в змозі побачити нічого на консолі.
Вітторіо Коцзоліно

3
Насправді він працює чудово в моїй оболонці Spark, навіть в 1.2.0. Але я думаю, я знаю, звідки походить ця плутанина: в оригінальному запитанні було задано питання про те, як надрукувати RDD на консолі Spark (= оболонки), тому я припускав, що він запустить локальну роботу, і в цьому випадку foreachпрацює добре. Якщо ви виконуєте завдання на кластері і хочете роздрукувати свій rdd, вам слід collect(як вказують інші коментарі та відповіді), щоб воно було надіслано драйверу до того, як printlnбуде виконано. І використання, takeяк запропонував Oussama, може бути хорошою ідеєю, якщо ваш RDD занадто великий.
fedragon

6
Вищеназвана відповідь погана. Ви повинні неприйняти це. Foreach не надрукує на консолі, він надрукує на робочих вузлах. Якщо у вас є лише один вузол, то foreach працюватиме. Але якщо у вас лише один вузол, то чому ви використовуєте іскру? Просто використовуйте SQL awk, або Grep, або щось набагато простіше. Тож я думаю, що єдиною правильною відповіддю є збір. Якщо збір великий для вас, і ви хочете лише зразок, використовуйте функції take, head або simillar, як описано нижче.
eshalev

12

Якщо ви запускаєте це на кластері, то printlnвін не буде друкуватись у ваш контекст. Потрібно внести RDDдані до сеансу. Для цього ви можете примусити його до локального масиву, а потім роздрукувати:

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

12

Ви можете перетворити свою RDDна 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._
Райан Хартман

Для чого тут використовувалася бібліотека? Я не можу виявити toDFні spark.implicits._в області іскри.
Сергій

1

Мабуть, існує багато архітектурних відмінностей між myRDD.foreach(println)і myRDD.collect().foreach(println)(не тільки "збирати", але й іншими діями). Одна з відмінностей, яку я бачив - це робити myRDD.foreach(println), вихід буде у випадковому порядку. Наприклад: якщо мій rdd надходить із текстового файлу, де кожен рядок має номер, вихід буде мати інший порядок. Але коли я це зробив myRDD.collect().foreach(println), замовлення залишається таким же, як текстовий файл.


1

В пітоні

   linesWithSessionIdCollect = linesWithSessionId.collect()
   linesWithSessionIdCollect

Це дозволить роздрукувати весь вміст RDD


1
Дякую, але я позначив це питання scala не python
blue-sky


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

Важливо

Це має сенс лише в тому випадку, якщо ви працюєте в локальному режимі та маєте невеликий набір даних. В іншому випадку ви або не зможете побачити результати на клієнті або не вистачить пам’яті через великий результат набору даних.



Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.