Когда использовать UDF по сравнению с функцией в PySpark?

Я использую Spark с Databricks и имею следующий код:

def replaceBlanksWithNulls(column):
    return when(col(column) != "", col(column)).otherwise(None)

Оба следующих утверждения работают:

x = rawSmallDf.withColumn("z", replaceBlanksWithNulls("z"))

и используя UDF:

replaceBlanksWithNulls_Udf = udf(replaceBlanksWithNulls)
y = rawSmallDf.withColumn("z", replaceBlanksWithNulls_Udf("z"))

Из документации мне непонятно, когда я должен использовать один над другим и почему?


person Rodney    schedule 09.05.2019    source источник


Ответы (2)


По сути, UDF может быть любой функцией (конечно, есть исключения) — нет необходимости использовать структуры Spark, такие как when, col и т. д. Используя UDF, функцию replaceBlanksWithNulls можно записать как обычный код Python:

def replaceBlanksWithNulls(s):
    return "" if s != "" else None

который можно использовать в столбце фрейма данных после его регистрации:

replaceBlanksWithNulls_Udf = udf(replaceBlanksWithNulls)
y = rawSmallDf.withColumn("z", replaceBlanksWithNulls_Udf("z"))

Примечание. Тип возвращаемого значения по умолчанию для UDF — это строки. Если требуется другой тип, который необходимо указать при его регистрации, например.

from pyspark.sql.types import LongType
squared_udf = udf(squared, LongType())

В этом случае операция столбца не сложна, и есть функции Spark, которые могут достичь того же (т.е. replaceBlanksWithNulls, как в вопросе:

x = rawSmallDf.withColumn("z", when(col("z") != "", col("z")).otherwise(None))

Это предпочтительнее всегда, когда это возможно, поскольку позволяет Spark оптимизировать запрос, см., например, Функции Spark и производительность UDF?

person Shaido    schedule 09.05.2019
comment
Спасибо за объяснение - я обнаружил, что написание встроенного кода PySpark (что более эффективно) означает повторное использование кода. Для простого примера предположим, что я хочу расширить функцию replaceBlanksWithNulls, а также заменить NAN или другое значение на null. Вместо того, чтобы просто изменить его в одном месте, мне нужно найти все места, где я использовал встроенный код. Так что это может быть более эффективно, но я считаю, что это не очень хорошо подходит для повторного использования... мыслей? - person Rodney; 21.05.2019
comment
@Rodney: я бы рекомендовал вам продолжать использовать такие методы, как метод replaceBlanksWithNulls в вашем вопросе. Это не udf, поскольку он возвращает выражение, которое можно использовать для одного или нескольких столбцов. Производительность этого подхода эквивалентна обычному встроенному коду, но позволяет создавать расширения в одном месте. - person Shaido; 21.05.2019

Вы можете найти разницу в Spark SQL (как указано в документе). Например, вы можете найти это, если напишете:

spark.sql("select replaceBlanksWithNulls(column_name) from dataframe")

не работает, если вы не зарегистрировали функцию replaceBlanksWithNulls как udf. В spark sql нам нужно знать возвращаемый тип функции для выполнения. Следовательно, нам нужно зарегистрировать пользовательскую функцию как определяемую пользователем функцию (udf) для использования в spark sql.

person OmG    schedule 09.05.2019
comment
Спасибо - так вы говорите, что в PySpark нет никакой разницы (например, производительность такая же? - person Rodney; 09.05.2019
comment
@Родни, с удовольствием. на этот вопрос дан ответ stackoverflow.com/q/38296609/3768871, как указано в ответе Шайдо. - person OmG; 09.05.2019