Spark: UDF eseguito più volte


9

Ho un dataframe con il seguente codice:

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"))

Ora controllando i registri, ho scoperto che per ogni riga l'UDF viene eseguito 3 volte. Se aggiungo "test3" da una colonna "test.three", l'UDF viene eseguito ancora una volta.

Qualcuno può spiegarmi perché?

Questo può essere evitato correttamente (senza memorizzare nella cache il frame di dati dopo aver aggiunto "test", anche se funziona)?


Cosa intendi? Stai chiamando la funzione test tre volte. Ecco perché viene eseguito tre volte. Non so perché lo stai trasformando in un UDF. Perché non trasformare semplicemente la mappa in val?
user4601931

Questo è solo un esempio per mostrare il comportamento di Spark. Per me "test" è una nuova colonna che contiene una struttura, quindi l'accesso a qualsiasi parte della struttura non dovrebbe eseguire nuovamente l'UDF. Come sbaglio?
Rolintocour,

Ho provato a stampare lo schema, il DataType di "test" è Mape non un Struct. Ora invece di restituire una mappa, se l'UDF restituisce una classe case come Test (una stringa, due: stringa), allora testè effettivamente uno Struct ma ci sono sempre tante esecuzioni dell'UDF.
Rolintocour,


la memorizzazione nella cache dovrebbe funzionare in base a questa risposta: stackoverflow.com/a/40962714/1138523
Raphael Roth

Risposte:


5

Se vuoi evitare più chiamate a un udf (che è utile soprattutto se udf è un collo di bottiglia nel tuo lavoro) puoi farlo come segue:

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

Fondamentalmente dici a Spark che la tua funzione non è deterministica e ora Spark si assicura che venga chiamata una sola volta perché non è sicuro chiamarla più volte (ogni chiamata potrebbe eventualmente restituire risultati diversi).

Inoltre, tieni presente che questo trucco non è gratuito, in questo modo stai ponendo alcuni vincoli all'ottimizzatore, un effetto collaterale di questo è ad esempio che l'ottimizzatore Spark non spinge i filtri attraverso espressioni che non sono deterministiche, quindi diventi responsabile dell'ottimale posizione dei filtri nella query.


simpatico! questa risposta appartiene anche qui: stackoverflow.com/questions/40320563/…
Raphael Roth

Nel mio caso, asNondeterministiccostringe l'UDF ad eseguire una sola volta. Con la explode(array(myUdf($"id")))soluzione, viene comunque eseguita due volte.
Rolintocour,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.