繁体   English   中英

如何在不指定每一列的情况下将整行作为参数传递给Spark(Java)中的UDF?

[英]How to pass the whole row as an argument to an UDF in Spark (Java) without specifying every column?

我有这个Java代码,其中spark UDF将Row作为输入并返回Row。 还有一个广播变量,它是HashMap。

UDF所做的只是检查广播的HashMap是否包含rowKey,如果包含,则返回一个新行,其中包含来自输​​入行的一些现有值和广播的HashMap的一些更新值。 如果不是,则按原样返回输入行。 我这样做是因为我想根据HashMap中的值更新行列的值。 这是代码:

广播变量

final Broadcast<HashMap<String, HashMap<String, String>>> broadcastVariable = jsc.broadcast(someHashMap);

UDF定义

UDF1<Row, Row> myUDF = new UDF1<Row, Row> () {
    @Override
    public Row call(Row inputRow) {

        String myKey = inputRow.getString(3);

        if (broadcastVariable.value().containsKey(myKey)){
            Map<String, String> valuesToUpdate = broadcastVariable.value().get(myKey);

            String col1 = inputRow.getString(0);
            String col2 = inputRow.getString(1);
            String col3 = inputRow.getString(2);

            for (Map.Entry<String, String> entry : valuesToUpdate.entrySet())
            {
                String columnName = entry.getKey();

                switch(columnName) {
                case "col1" :
                    col1 = entry.getValue();
                    break;
                case "col2" :
                    col2 = entry.getValue();
                    break;
                case "col3" :
                    col3 = entry.getValue();
                    break;
                }
            }
            return RowFactory.create(col1,col2,col3,myKey);

        }
        return inputRow;
    }
};

UDF注册

hiveContext.udf().register("myUDF", myUDF, DataTypes.createStructType(DF1.schema().fields()));

UDF通话

DataFrame DF2 = DF1.select(org.apache.spark.sql.functions.callUDF
                ("myUDF", org.apache.spark.sql.functions.struct(DF1.col("col1"),
                        DF1.col("col2"),
                        DF1.col("col3"),
                        DF1.col("myKey"))));

我有以下问题,

  1. 如何将数据框中的所有列传递给UDF,而不一一列出? 我要问的原因是实际的DataFrame有超过50列。 我看到了这个示例 ,但是无法使其在Java中工作。

  2. 有没有一种方法可以在UDF中按名称访问行列? 现在我正在使用getString(int)。

  3. UDF输出是名称为myUDF(struct(col1,col2,col3,myKey))的Struct。 超过50列会变得很长。 我该如何别名?

任何帮助表示赞赏!

TL; DR使用Dataset.map (并将UDF替换为map函数)。


如何将数据框中的所有列传递给UDF,而不一一列出?

dataframe.schema.fieldNames

请参阅数据集 API。

有没有一种方法可以在UDF中按名称访问行列?

引用Row.fieldIndex的scaladoc

fieldIndex(name:String):Int返回给定字段名称的索引。

并使用索引。

超过50列会变得很长。 我该如何别名?

看起来您的代码将从某些重构和组合中受益。 在单个管道中处理50个字段可能会有些麻烦。

您无需事先知道列名!

您可以将Row类型作为udf的参数之一。 例如:

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

val myUdf = udf((row: Row) => <here comes the code inside your udf>)

您可以这样称呼udf:

df.withColumn(newColumnName, myUdf(struct(df.columns map col: _*)))

然后您可以访问udf中的数据框行(结构和数据)以获取所需的任何内容,例如-将行转换为(column_name-> column_value)的映射:

val myUdf = udf((row: Row) => row.getValuesMap(row.schema.fieldNames))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM