UDF не поддерживают varargs *, но вы можете передать произвольное количество столбцов, завернутых с помощью функции array
:
import org.apache.spark.sql.functions.{udf, array, lit}
val myConcatFunc = (xs: Seq[Any], sep: String) =>
xs.filter(_ != null).mkString(sep)
val myConcat = udf(myConcatFunc)
Пример использования:
val df = sc.parallelize(Seq(
(null, "a", "b", "c"), ("d", null, null, "e")
)).toDF("x1", "x2", "x3", "x4")
val cols = array($"x1", $"x2", $"x3", $"x4")
val sep = lit("-")
df.select(myConcat(cols, sep).alias("concatenated")).show
// +------------+
// |concatenated|
// +------------+
// | a-b-c|
// | d-e|
// +------------+
С сырым SQL:
df.registerTempTable("df")
sqlContext.udf.register("myConcat", myConcatFunc)
sqlContext.sql(
"SELECT myConcat(array(x1, x2, x4), '.') AS concatenated FROM df"
).show
// +------------+
// |concatenated|
// +------------+
// | a.c|
// | d.e|
// +------------+
Немного более сложный подход не использует UDF вообще и составляет выражения SQL с примерно чем-то примерно следующим образом:
import org.apache.spark.sql.functions._
import org.apache.spark.sql.Column
def myConcatExpr(sep: String, cols: Column*) = regexp_replace(concat(
cols.foldLeft(lit(""))(
(acc, c) => when(c.isNotNull, concat(acc, c, lit(sep))).otherwise(acc)
)
), s"($sep)?$$", "")
df.select(
myConcatExpr("-", $"x1", $"x2", $"x3", $"x4").alias("concatenated")
).show
// +------------+
// |concatenated|
// +------------+
// | a-b-c|
// | d-e|
// +------------+
, но я сомневаюсь стоит усилий, если вы не работаете с PySpark.
* Если вы передадите функцию с использованием varargs, она будет удалена из всего синтаксического сахара, и в результате UDF ожидает ArrayType
. Например:
def f(s: String*) = s.mkString
udf(f _)
будет иметь тип:
UserDefinedFunction(<function1>,StringType,List(ArrayType(StringType,true)))
Как сказал Бо в своем комментарии, раздел .text
доступен только для чтения по текущим системам. Чтобы этот код работал, вы должны сделать его доступным для записи. Например, вы можете использовать директиву в исходном файле:
.section wtext, "awx", @progbits
Эквивалентная nasm
директива:
section wtext exec write
В качестве альтернативы, также можно передать -N
переключиться на компоновщик.
Обратите внимание, что такой код оболочки обычно предназначен для выполнения стека, что является еще одной вещью, которая обычно отключается в текущих операционных системах. Если вы когда-нибудь захотите попробовать это в стеке, вам может понадобиться опция -z execstack
компоновщика.