将超过22列传递到Spark Java中的UDF

时间:2019-01-13 13:19:30

标签: java apache-spark apache-spark-sql

我有一个用我的Spark Java代码编写的UDF,我想在其中传递超过22列(恰好是24列)。但是Spark API仅允许最多22列,是否有任何技巧可以覆盖此列,还是可以创建自定义UDF函数来覆盖此限制?

3 个答案:

答案 0 :(得分:0)

您可以传递复杂类型的列。最通用的解决方案是Struct,但您也可以考虑使用Array或Map。

地图示例中的参数:

    val df = sc.parallelize(Seq(("a","b"),("c","d"), 
      ("e","f"))).toDF("one","two")


     val myUDF = udf((input:Map[String,String]) => {
      // do something with the input
       input("one")=="a"
       })

     df
    .withColumn("udf_args",map(
       lit("one"),$"one",
        lit("two"),$"one"
      )
    )
    .withColumn("udf_result", myUDF($"udf_args"))
     .show()

答案 1 :(得分:0)

您可以将列值的数组传递给udf,而不是传递24个列值,并且操作将在该数组上。 这是示例代码:

import org.apache.spark.sql.functions._
import org.apache.spark.sql.expressions.UserDefinedFunction

case class department(id: Integer, deptname: String)
import spark.implicits._
val df1 = Seq(department(1, "physics")
      , department(2, "computer")).toDF()
val df2 = df1.withColumn("all_col", array($"id", $"deptname"))
val concat_udf:UserDefinedFunction = udf((all_col_values:Seq[String]) => {
      (all_col_values(0) + "-" + all_col_values(1))
    })
//apply udf
val df3 = df2.withColumn("all_col_concat",concat_udf(col("all_col")))
df3.show()

其他: 如果可以在没有udf的情况下在每行上应用匿名函数,则可以尝试这种方式,但是不确定是否可以满足要求。

import org.apache.spark.sql.Row
val df4 = df1.rdd.map{ case Row(id:Integer, deptname:String) => (id, deptname,id.toString()+"-"+deptname)}.
          toDF("id","deptname", "all_col_concat")
df4.show()

答案 2 :(得分:0)

我看到很多答案都是用scala编写的,正如您在spark java中所要求的那样,我将用Java重写它。答案也可以在任意列中使用。

import static org.apache.spark.sql.functions.array;

List<Column> cols =  Arrays.asList(new Column[] {ds.select("col1"), ds.select("col2") ...});// all the columns
Column mergedCol = array(cols.toArray(new Column[cols.size()])); //merge all your cols
//udf
UserDefinedFunction myUdf = udf(
    (Seq<Object> seq) -> {
        //you should have 24 Objects here. 
        for (Object o : JavaConverters.seqAsJavaListConverter(seq).asJava()) {                  
                ...         
        );
    },
    DataTypes.[your data type]);
//use it as
ds.select(myUdf.apply(mergedCol));