Spark: UDF executado várias vezes


9

Eu tenho um quadro de dados com o seguinte código:

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

Agora, verificando os logs, descobri que para cada linha a UDF é executada 3 vezes. Se eu adicionar o "test3" de uma coluna "test.three", o UDF será executado novamente.

Alguém pode me explicar o porquê?

Isso pode ser evitado corretamente (sem armazenar em cache o quadro de dados após a adição de "teste", mesmo que isso funcione)?


O que você quer dizer? Você está chamando a função de teste três vezes. É por isso que está sendo executado três vezes. Não sei por que você está criando uma UDF. Por que não fazer do mapa apenas um valor?
user4601931

Este é apenas um exemplo para mostrar o comportamento da faísca. Para mim, "test" é uma nova coluna que contém uma estrutura; o acesso a qualquer parte da estrutura não deve executar o UDF novamente. Como eu estou errado?
Rolintocour 4/11/19

Eu tentei imprimir o esquema, o DataType de "teste" é Mape não um Struct. Agora, em vez de retornar um mapa, se o UDF retornar uma classe de caso como Test (uma String, duas: String), na testverdade, é uma Struct, mas sempre haverá muitas execuções da UDF.
Rolintocour 4/11/19


caching deve funcionar de acordo com esta resposta: stackoverflow.com/a/40962714/1138523
Raphael Roth

Respostas:


5

Se você deseja evitar várias chamadas para um udf (o que é útil especialmente se o udf é um gargalo no seu trabalho), você pode fazer o seguinte:

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

Basicamente, você diz ao Spark que sua função não é determinística e agora o Spark garante que ele seja chamado apenas uma vez porque não é seguro chamá-lo várias vezes (cada chamada pode retornar um resultado diferente).

Lembre-se também de que esse truque não é gratuito. Ao fazer isso, você está colocando algumas restrições no otimizador; um efeito colateral disso é, por exemplo, que o otimizador Spark não envia filtros através de expressões que não são determinísticas, para que você se torne responsável pela otimização ideal. posição dos filtros na sua consulta.


agradável! esta resposta também pertence aqui: stackoverflow.com/questions/40320563/...
Raphael Roth

No meu caso, asNondeterministicobriga a UDF a executar apenas uma vez. Com a explode(array(myUdf($"id")))solução, ele ainda é executado duas vezes.
Rolintocour 5/11/19
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.