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 потребуют сериализации и десериализации данных.