2016-08-24 86 views
0

我需要幫助來迭代Spark-Scala中用DataFrame編寫的這段代碼。我是Scala的新手,所以我很抱歉如果我的問題看起來微不足道。模式匹配的Scala迭代器

該函數非常簡單:給定一個數據框,如果存在模式匹配,則函數會轉換列,否則選擇所有字段。

/* Load sources */ 
val df = sqlContext.sql("select id_vehicle, id_size, id_country, id_time from " + working_database + carPark); 


val df2 = df.select(
     df.columns.map { 
     case id_vehicle @ "id_vehicle" => df(id_vehicle).cast("Int").as(id_vehicle) 
     case other   => df(other) 
     }: _* 
    ) 

此功能,用模式匹配,完美的作品!

現在我有一個問題:有什麼辦法可以「迭代」這個嗎?在實踐中,我需要給定一個dataframe一個函數,一個列(COLUMN_1,COLUMN_2,...)Array[String]類型(INT,雙,浮法,...)的另一個Array[String],回到我同樣的dataframe右轉右轉。

我需要幫助:)

+0

當你說你的函數需要兩個數組。第一列名稱是否轉到其他數組中的第一個類型。所以他們總是有相同的長度? –

+0

是的,長度一樣!否則會發生錯誤! – Alessandro

回答

1
//Your supplied code fits nicely into this function 
def castOnce(df: DataFrame, colName: String, typeName: String): DataFrame = { 
    val colsCasted = df.columns.map{ 
     case colName => df(colName).cast(typeName).as(colName) 
     case other => df(other) 
    } 
    df.select(colsCasted:_ *) 
} 

def castMany(df: DataFrame, colNames: Array[String], typeNames: Array[String]): DataFrame = { 

    assert(colNames.length == typeNames.length, "The lengths are different") 
    val colsWithTypes: Array[(String, String)] = colNames.zip(typeNames) 
    colsWithTypes.foldLeft(df)((cAndType, newDf) => castOnce(newDf, cAndType._1, cAndType._2)) 
} 

當你有,你只需要多次適用於摺疊往往是你想要的東西同樣的事情的功能。 上面的代碼將兩個數組拉到一起,將它們合併爲一個。 然後它遍歷這個列表,每次應用你的函數到數據框,然後將下一對應用到結果數據框等。

根據你的編輯,我填寫了上面的函數。我沒有編譯器,所以我不能100%確定它的正確性。寫完後,我還在質疑我原來的做法。以下是我相信的一種更好的方式,但我將離開前一個參考。

def(df: DataFrame, colNames: Array[String], typeNames: Array[String]): DataFrame = { 
    assert(colNames.length == typeNames.length, "The lengths are different") 
    val nameToType: Map[String, String] = colNames.zip(typeNames).toMap 
    val newCols= df.columns.map{dfCol => 
     nameToType.get(dfCol).map{newType => 
      df(dfCol).cast(newType).as(dfCol) 
     }.getOrElse(df(dfCol)) 
    } 
    df.select(newCols:_ *) 
} 

上面的代碼創建一個列名到所需類型的映射。 然後,在數據框的foreach列中,它看起來是Map中的類型。 如果類型存在,我們將該列轉換爲該新類型。如果該列不存在於Map中,那麼我們直接默認從DataFrame中的列。

然後我們從DataFrame中選擇這些列

+0

謝謝你的回覆:)但是,爲了理解這個概念,我需要多一點幫助。我的代碼現在不工作: '高清castOnce(DF:數據幀,COLNAME:字符串參數typeName:字符串):數據幀= { \t df.select( \t \t df.columns.map { \t \t \t情況X @ COLNAME => DF(X).cast(typeName的)。如(X) \t \t \t情況之外=> DF(其他) \t \t}:_ * \t \t \t ) }' 現在我無法迭代,因爲castOnce函數是錯誤的:我如何遍歷colName? 如果我把「somethig」這樣的簡單字符串放在'case x @ colName:String \t => df(x).cast(typeName)行中。作爲(x)代碼有效,但我必須迭代。 – Alessandro

+0

在您的代碼中,現在,您發佈的兩個函數都有相同的錯誤: 錯誤:重載的方法值選擇替換項: col:String,cols:String *)org.apache.spark.sql.DataFrame (cols:org.apache.spark.sql.Column *)org.apache.spark.sql.DataFrame 不能應用於(Array [org.apache.spark.sql.Column]) df.select(newCols)//或df.select(colsCasted)' 我明白這個概念,無論如何我必須告訴你:謝謝!第二個功能非常緊湊,所以最好使用它! – Alessandro

+0

很高興我能幫上忙。我想我解決了編譯錯誤,以供將來參考。 –