Spark:UDFが何度も実行された


9

次のコードのデータフレームがあります。

def test(lat: Double, lon: Double) = {
  println(s"testing ${lat / lon}")
  Map("one" -> "one", "two" -> "two")
}

val testUDF = udf(test _)

df.withColumn("test", testUDF(col("lat"), col("lon")))
  .withColumn("test1", col("test.one"))
  .withColumn("test2", col("test.two"))

ログを確認したところ、行ごとにUDFが3回実行されていることがわかりました。「test.three」列から「test3」を追加すると、UDFがもう一度実行されます。

なぜ誰かが私に理由を説明できますか?

これは適切に回避できますか?


どういう意味ですか?テスト関数を3回呼び出しています。そのため、3回実行されます。なぜUDFにするのかわかりません。なぜマップをただの値にしないのですか?
user4601931

これは、スパークの動作を示すための単なる例です。私にとって「テスト」は構造を含む新しい列であり、構造の任意の部分にアクセスしてもUDFを再度実行するべきではありません。どうしたの?
Rolintocour

スキーマを印刷しようとしましたが、 "test"のDataTypeはMapStructではありません。マップを返す代わりに、UDFがTest(one String、two:String)のようなケースクラスを返す場合、test実際にはStructですが、UDFの実行は常に同じです。
Rolintocour


キャッシングはこの回答に従って機能するはずです:stackoverflow.com/a/40962714/1138523
Raphael Roth

回答:


5

udfへの複数の呼び出しを回避したい場合(特にudfがジョブのボトルネックである場合に役立ちます)、次のように実行できます。

val testUDF = udf(test _).asNondeterministic()

基本的には、Sparkに関数が確定的でないことを伝え、Sparkは複数回呼び出すのは安全ではないため、1回だけ呼び出されることを確認します(呼び出しごとに異なる結果が返される可能性があります)。

このトリックは無料ではないことにも注意してください。これを行うと、オプティマイザにいくつかの制約が課されます。これの1つの副作用は、たとえば、Sparkオプティマイザが決定論的でない式を通じてフィルタをプッシュしないため、最適化の責任を負うことになります。クエリ内のフィルターの位置。


いいね!この答えはここにも所属:stackoverflow.com/questions/40320563/...
ラファエル・ロス

私の場合、asNondeterministicUDF は強制的に1回だけ実行されます。このexplode(array(myUdf($"id")))ソリューションでは、2回実行されます。
Rolintocour
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.