我有这个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"))));
我有以下问题,
如何将数据框中的所有列传递给UDF而不逐一列出?我问这个的原因是实际的DataFrame有50多列。我看到了这个example,但无法用Java工作。
有没有办法可以在UDF中按名称访问行列?现在我正在使用getString(int)。
UDF输出是一个名为myUDF的struct(struct(col1,col2,col3,myKey))。它有50多列,真的很长。我该怎么做呢?
感谢任何帮助!
答案 0 :(得分:2)
TL; DR 使用Dataset.map(并使用map
函数替换UDF。
如何将数据框中的所有列传递给UDF而不逐一列出?
dataframe.schema.fieldNames
请参阅Dataset API。
有没有办法可以在UDF中按名称访问行列?
引用Row.fieldIndex的scaladoc:
fieldIndex(name:String):Int 返回给定字段名称的索引。
并使用索引。
50多列真的很长。我该怎么做呢?
看起来你的代码会从一些重构和组合中受益。在单个管道中使用50个字段可能会有点笨拙。
答案 1 :(得分:-1)
您不需要事先知道列名!
您可以将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))