На самом деле, это очень просто.
В вашем случае ничего нельзя пропустить, так как каждое действие имеет свой тип JOIN. Нужно сканировать d и d ', чтобы вычислить результат. Даже с .cache (который вы не используете и должны использовать, чтобы избежать повторного вычисления до исходного кода для каждого действия), это не имеет значения.
Глядя на эту упрощенную версию:
val d = sc.parallelize(0 until 100000).map(i => (i%10000, i)).cache // or not cached, does not matter
val c=d.rightOuterJoin(d.reduceByKey(_+_))
val f=d.leftOuterJoin(d.reduceByKey(_+_))
c.count
c.collect // skipped, shuffled
f.count
f.collect // skipped, shuffled
Показывает следующие задания для этого приложения:
(4) Spark Jobs
Job 116 View(Stages: 3/3)
Job 117 View(Stages: 1/1, 2 skipped)
Job 118 View(Stages: 3/3)
Job 119 View(Stages: 1/1, 2 skipped)
Вы можете видеть, что последовательные действия на основе тот же результат перетасовки вызывают пропуск одного или нескольких этапов для второго действия/ Работа для val c или val f. То есть, тип соединения для c и f известен, и 2 действия для одного и того же типа соединения выполняются последовательно, извлекая выгоду из предыдущей работы, то есть второе действие может полагаться на перетасовку первого действия, которое непосредственно применимо ко 2-му действию. Действие. Это просто.