Spark sql - использовать преобразование строк или UDF

У меня есть таблица ввода (I) со 100 столбцами и 10 миллионами записей. Я хочу получить таблицу вывода (O), которая имеет 50 столбцов, и эти столбцы выводятся из столбцов I, т.е. Будет 50 функций, которые отображают столбцы I-50 столбцов O, т.е. o1 = f (i1), o2 = f (i2, i3)..., o50 = f (i50, i60, i70).

В искровом sql я могу сделать это двумя способами:

  • преобразование строк, где целая строка я анализируется (например: функция карты) один за другим, чтобы создать строку O.
  • Используйте UDF, который, как я полагаю, работает на уровне столбца, то есть беру существующие столбцы я в качестве входных данных и создаю один из соответствующих столбцов O i.e используйте 50 функций UDF.

Я хочу знать, какой из вышеперечисленных 2 более эффективен (более высокая распределенная и параллельная обработка) и почему или если они одинаково быстрые/эффективные, учитывая, что я обрабатываю всю входную таблицу я и производя полностью новую таблицу вывода O т.е. его объемную обработку данных.

Ответы

Ответ 1

Я собирался написать все это о Оптимизатор Catalyst, но проще просто отметить, что говорит Яцек Ласковски в своей книге Освоение Apache Spark 2:

"Используйте стандартные функции на основе столбца на высоком уровне с операторами Dataset, когда это возможно, прежде чем вернуться к использованию собственных пользовательских функций UDF, поскольку UDF являются черным ящиком для Spark и поэтому даже не пытаются их оптимизировать".

Jacek также замечает комментарий от кого-то из команды разработчиков Spark:

"Существуют простые случаи, когда мы можем анализировать байтовый код UDF и выводить то, что он делает, но это довольно сложно сделать в целом".

Вот почему Spark UDF никогда не должны быть вашим первым вариантом.

То же самое чувство повторяется в этой статье Cloudera , где автор заявляет: "... используя встроенные функции запросов SQL Apache Sparks часто будет приводить к наилучшей производительности и должен быть первым рассмотренным подходом, когда можно вводить UDF".

Однако автор правильно отмечает также, что это может измениться в будущем, поскольку Spark станет более умным, и тем временем вы можете использовать Expression.genCode, как описано в Chris Freglys talk, если вы не против жесткой связи с оптимизатором Catalyst.

Ответ 2

Пользовательские функции или пользовательские функции могут быть определены и зарегистрированы как UDF в Spark SQL с ассоциированным псевдонимом, доступным для SQL-запросов.

UDF оказывает значительное влияние на производительность Apache Spark SQL (Оптимизатор оптимизаторов SQL Spark)

Поскольку у нас нет определенных правил в Spark, разработчик может использовать его/ее должную осмотрительность.

Python UDF никогда не использует UDF. невозможно компенсировать затраты на повторную сериализацию, десериализацию и перемещение данных между интерпретатором Python и JVM, результаты UDF Python приводятся в результате сериализации данных между JVM-исполнителем и интерпретатором Python с использованием логики UDF - это значительно снижает производительность по сравнению с реализациями UDF в Java или Scala.

Java, Scala UDF реализация доступна непосредственно исполнителем JVM. Итак, Java, Scala производительность UDF лучше, чем Python UDF

Функции Spark SQL работают непосредственно на JVM и оптимизируются как с Catalyst, так и с Tungsten. Это означает, что они могут быть оптимизированы в плане выполнения, и большую часть времени может извлечь выгоду из оптимизации кода и других вольфрама. Более того, они могут работать с данными в своем "родном" представлении., Поскольку Spark SQL работает с оптимизатором запросов Catalyst. Его возможности расширяются с каждым выпуском и часто обеспечивают значительное улучшение производительности для запросов Spark SQL;

Заключение: Код реализации UDF может быть не совсем понятен Catalyst, поэтому использование встроенных функций SQL-запросов Apache Sparks часто приводит к максимальной производительности и должно быть первым рассмотренным при каждом использовании UDF.

Ответ 3

В простых случаях использование UDF - намного лучший выбор, потому что он не требует полной кодировки и декодирования. UDF может получить доступ только к обязательным полям и закодировать результат.

Так как Spark 2.0 также намного лучше поддерживается и может быть в некоторой степени оптимизирован в плане выполнения.

Оба отображения полного Row и применения стандартного UDF не могут быть полезны для всех оптимизаций Spark SQL и нет разницы в распределении и распараллеливании данных.

Ответ 4

Spark имеет встроенные функции, чтобы иметь new dataframe, используя столбцы parent dataframe.

Эти функции будут работать лучше, чем два предложенных варианта использования функций udf или с помощью преобразований row.

Написание row функций преобразования для 50 обязательных столбцов итоговой таблицы с учетом оптимизированного распределения данных было бы настоящей проблемой.

Если ваши функции (o1 = f(i1) , o2 = f(i2, i3) ..., o50 = f(i50, i60, i70)) не могут быть заменены встроенными функциями или их комбинацией, то только я предлагаю вам используйте функции udf, так как функции udf потребуют сериализации и десериализации данных.