Кэширование и persist: когда помогает, а когда делает хуже
Кэш нужен ровно в одном случае: датафрейм используется несколько раз, а пересчёт дороже хранения. Без кэша каждое действие проходит цепочку с начала, включая повторное чтение файлов; с кэшем результат остаётся в памяти исполнителей. Тонкость первая: cache() ленив — до первого действия в памяти ничего нет, и это действие работает дольше обычного. Тонкость вторая: cache() — это persist(MEMORY_AND_DISK), и если данные не влезли, недостающие партиции уезжают на диск, а не пересчитываются; кэш датафрейма при этом хранится в JVM в колоночном формате Spark, поэтому язык клиента на него не влияет. Вредит кэш, когда датафрейм используется один раз (лишняя работа и занятая память), когда он огромен (вытесняет память выполнения и провоцирует OOM), и когда его забыли освободить — unpersist() не вызывается автоматически. Часто дешевле не кэшировать, а записать промежуточный результат в Parquet и прочитать заново.