如何在Java中实现scala的以下代码段

如何在Java中实现scala的以下代码段,java,scala,apache-spark,Java,Scala,Apache Spark,我正在实现一个代码来动态地将多个列添加到一个数据帧中,其中的行中有空值 我在scala中找到了以下代码片段,其中使用了Dataframe对象的映射函数 import org.apache.spark.sql.catalyst.encoders.RowEncoder import org.apache.spark.sql.types.{DataTypes, NullType, StructType} import org.apache.spark.sql.{DataFrame, Encoders,

我正在实现一个代码来动态地将多个列添加到一个数据帧中,其中的行中有空值

我在scala中找到了以下代码片段,其中使用了Dataframe对象的映射函数

import org.apache.spark.sql.catalyst.encoders.RowEncoder
import org.apache.spark.sql.types.{DataTypes, NullType, StructType}
import org.apache.spark.sql.{DataFrame, Encoders, Row, SparkSession}
import org.apache.spark.sql.functions.lit;

def addColumnsViaMap(df: DataFrame, words: List[String]): DataFrame = {
   val encoder = RowEncoder.apply(getSchema(df, words))
   df.map(mappingRows(df.schema)(words))(encoder)
}

private val mappingRows: StructType => List[String] => Row => Row =
  (schema) => (words) => (row) => {
     val addedCols: List[Any] = words.map(_=> null)
    Row.merge(row, Row.fromSeq(addedCols))
  }

private def getSchema(df: DataFrame, words: List[String]): StructType = {
  var schema: StructType = df.schema
  words.foreach(word => schema = schema.add(word, "string", false))
  schema
}
我已经用java实现了以下两个函数

 private StructType getSchema(Dataset<Row> df, List<String> cols){
        StructType schema = df.schema();
        cols.forEach(col -> schema.add(col, "int", true));
        return schema;
    }

private addColumnsViaMap(Dataset<Row> df, List<String> cols){
    Encoder<Row> encoder1 = 
  RowEncoder.apply(dataConsolidationEngine.getSchema(df,cols));
   df.map(new MapFunction<Set<String>, Row>() {
                private static final long serialVersionUID = 1L;

                @Override
                public Row call(Set<String> cols) throws Exception {
                    // TODO Auto-generated method stub
                }
            }, encoder1);
}
private StructType getSchema(数据集df,列表cols){
StructType schema=df.schema();
forEach(col->schema.add(col,“int”,true));
返回模式;
}
私有addColumnsIAMAP(数据集df,列表列){
编码器1=
应用(dataConsolidationEngine.getSchema(df,cols));
map(新的MapFunction(){
私有静态最终长serialVersionUID=1L;
@凌驾
公用行调用(Set cols)引发异常{
//TODO自动生成的方法存根
}
},编码器1);
}
由于参数不匹配,addColumnsViaMap方法在解析匿名映射函数方法时出现编译错误

我不理解mappingRows的scala代码,尤其是下面的
StructType=>List[String]=>Row=>Row=
(模式)=>(单词)=>(行)
这是什么意思

如何在Java中实现上述scala代码?

private val mappingRows:StructType=>List[String]=>Row=>=
(架构)=>(单词)=>(行)=>{
val addedCols:List[Any]=words.map(=>null)
行合并(行,行fromSeq(addedCols))
}
简言之,这可以理解为:

mappingRows
是一个“函数”,它接受3个参数(类型分别为
StructType
List
Row
,例如schema、words和Row),并返回一个
行。但不是这样称呼它:

mappingRows(模式、单词、行)`
你会去的

mappingRows(模式)(单词)(行)
这意味着打电话只是

mappingRows(模式)(单词)
将返回一个函数,该函数接受
,并返回
:一个映射函数,可以传递给典型的
.map()
函数

基本上,给定一个模式和一列列列名称,闭包接受一行作为输入。对于每个给定的col名称,它只是将null列添加到该行中

这有助于回答您的问题吗?

private val mappingRows:StructType=>List[String]=>Row=>Row=
(架构)=>(单词)=>(行)=>{
val addedCols:List[Any]=words.map(=>null)
行合并(行,行fromSeq(addedCols))
}
简言之,这可以理解为:

mappingRows
是一个“函数”,它接受3个参数(类型分别为
StructType
List
Row
,例如schema、words和Row),并返回一个
行。但不是这样称呼它:

mappingRows(模式、单词、行)`
你会去的

mappingRows(模式)(单词)(行)
这意味着打电话只是

mappingRows(模式)(单词)
将返回一个函数,该函数接受
,并返回
:一个映射函数,可以传递给典型的
.map()
函数

基本上,给定一个模式和一列列列名称,闭包接受一行作为输入。对于每个给定的col名称,它只是将null列添加到该行中


这有助于回答您的问题吗?

好吧,这个声明有点复杂(我也有点不可读),所以让我们退一步

在scala中,
字符串
列表
。。。是每个人都知道的类型。您可以创建类型为
String
的变量

您还可以将函数赋值给变量(这是scala的函数方向),这样函数也有类型。例如,如果您有一个函数,它接受一个
列表
并输出一个
字符串
,那么它的类型是
List=>String

这在代码中看起来像吗

// A list of strings
val names = List("alice", "bob")
// A function that takes a list and returns a string
def listToString(list: List[String]): String = list.mkString(",")
// We can assign the function to a variable
val myListToString: List[String] => String = listToString
但是我们有一个较短的函数声明符号,我们可以将它们声明为“inline”,而不使用
def
语句。这样就可以等效地编写上述代码:

val names = List("alice", "bob")
val myListToString: List[String] => String = (list) => list.mkString(",")
因此,一般来说:

  • A=>B
    是一种函数类型,它接受
    A
    并返回
    B
  • (arg:A)=>{new B()}
    是一个实际函数,它以
    A
    的一个实例作为输入(该实例绑定到变量名
    arg
    ,其主体返回B的一个实例)
现在让我们做一些疯狂的事情,让我们…重新开始。假设
F
是一个函数,它接受
列表
并返回
字符串
。一个接受
Int
并返回
F
的函数看起来像什么

那么应该是:

  • Int=>F
  • 也就是说:
    Int=>(List=>String)
  • 可以写入
    Int=>List=>String
你怎么申报呢

// Borrowing from above
val names = List("alice", "bob")
val myListToString: List[String] => String = (list) => list.mkString(",")
// now we're doing it
val intToListToString = (integerValue) => myListToString
// now we're doing it in one go
val intToListToString2 = (integerValue) => (list) => list.mkString(",")
这里,
intToListToString
是一个函数,它接受
int
并返回“一个接受
列表
并返回
字符串的函数”

你可以一次又一次地筑巢

直到您得到:
StructType=>List[String]=>Row=>Row
这是一种类型,意思是“一个函数,它以
StructType
作为输入并返回(一个函数,它以
List[String]
作为输入并返回一行))

您可以将其实现为:

(schema) => // a function that takes schema, and returns
    (words) => // a function that takes a list of words and returns
        (row) => // a function that takes a row and returns
            Row.fromSeq(...) // another row
现在在Java中会是什么样子

如果你想严格地转换它,你可以这样想:scala的
A=>B
的自然等价物是
java.util.Function
。最重要的是,如果你想使用一个函数来执行Spark
map
操作
schema ->  words -> row -> Row.merge(row, Row.fromSeq(Array.newInstance(String.class, words.size)))
import org.apache.spark.sql.DataFrame
def addColumnsViaMap(dataframe: DataFrame, words: List[String]) = words.foldLeft(dataframe)((df, word) => df.withColumn(word, lit(null: String)))

val dataframe = Seq(("a", "b"), ("c", "d")).toDF("columnA", "columnB")
val words = List("columnC", "columnD")
addColumnsViaMap(dataframe, words).show

+-------+-------+-------+-------+
|columnA|columnB|columnC|columnD|
+-------+-------+-------+-------+
|      a|      b|   null|   null|
|      c|      d|   null|   null|
+-------+-------+-------+-------+
DataFrame addColumnsViaMap(DataFrame dataframe, List<String> words) {
    for (String word: words) {
        dataframe = dataframe.withColumn(word, lit((String) null))
    }
    return dataframe;
}