Это связано с некоторой сложностью, и я могу быть неясным по некоторым основам. Здесь идет:
Как я понимаю, у искры есть «трансформации» и «действия». Преобразования лениво составляют описание того, что вы хотите сделать, и действия делают это. Это может повысить производительность (позволяя оптимизировать планы) или привести к дублированию усилий, если вы используете несколько действий на одном кадре данных, что приводит к многократному запуску преобразования. Чтобы избежать этого, .cache () говорит Spark фактически «сохранить свою работу», поэтому не следует продолжать вычислять фрейм данных, на котором вы его вызываете.
Моя проблема в том, что это не кажется делать это. У меня есть функция "Foo", которая выполняет много вычислений для создания (очень маленького) фрейма данных. Foo работает быстро, и я могу отобразить результат. У меня есть еще одна функция «Бар», которая выполняет кучу действий над кадром данных. Bar работает быстро с (большим) исходным вводом, но очень медленно с выводом foo, даже кэшируется и объединяется. Я также могу «форсировать» кеширование, записав вывод foo на диск, а затем перечитав его, после чего строка запускается быстро:
display(bar(bigDF)) //Fast!
val profile = foo(bigDF).coalesce(1).cache()
display(profile) //Also fast! (and profile only has 2 rows, ~80 columns)
display(bar(profile)) //Slow!
profile
.write.format("com.databricks.spark.csv")
.option("header", "true")
.save("filename.csv")
val dumb = spark.read.format("csv").option("header", "true").load("filename.csv")
display(bar(dumb)) //Fast again
Для меня это говорит о том, что .cache () работает не так, как я думаю - медленный вызов повторно вызывает вызовы преобразования в foo, если я не записываю его на диск и не заставляю его «забыть» свою историю. Может кто-нибудь объяснить, что мне не хватает?