2017-07-07 527 views
2

我從它看起來像一個SQL源的數據幀:根據列值對火花數據幀進行分區?

User(id: Long, fname: String, lname: String, country: String) 

[1, Fname1, Lname1, Belarus] 
[2, Fname2, Lname2, Belgium] 
[3, Fname3, Lname3, Austria] 
[4, Fname4, Lname4, Australia] 

我想分區和寫數據到CSV文件,其中每個分區是基於該國的首字母,所以白俄羅斯和比利時應一個在輸出文件,奧地利和澳大利亞在其他。

回答

2

這裏是你可以做什麼

import org.apache.spark.sql.functions._ 
//create a dataframe with demo data 
val df = spark.sparkContext.parallelize(Seq(
    (1, "Fname1", "Lname1", "Belarus"), 
    (2, "Fname2", "Lname2", "Belgium"), 
    (3, "Fname3", "Lname3", "Austria"), 
    (4, "Fname4", "Lname4", "Australia") 
)).toDF("id", "fname","lname", "country") 

//create a new column with the first letter of column 
val result = df.withColumn("countryFirst", split($"country", "")(0)) 

//save the data with partitionby first letter of country 

result.write.partitionBy("countryFirst").format("com.databricks.spark.csv").save("outputpath") 

編輯: 您還可以使用可以提高性能通過Raphel的建議作爲

substring(Column str, int pos, int len)子字符串開始的子字符串在str時,長度爲len的是 ; str是字符串類型或返回字節片段 陣列,在字節開始於POS,其長度爲LEN的時候str是 二進制類型

val result = df.withColumn("firstCountry", substring($"country",1,1)) 

,然後用寫

希望使用partitionby這個解決您的問題!

+0

除了這個問題之外,df.withColumn是否會影響性能,或者是否可以以更有效的方式完成? – jdk2588

+1

你也可以使用spark的'substring'函數代替'split',我認爲這樣更具可讀性 –

+0

我們可以用多列來做到這一點嗎? – user482963

0

解決此問題的一種替代方法是首先創建一個只包含每個國家的首字母的列。完成此步驟後,您可以使用partitionBy將每個分區保存爲單獨的文件。

dataFrame.write.partitionBy("column").format("com.databricks.spark.csv").save("/path/to/dir/") 
+0

這將在列值上創建分區,因此我們將爲單獨的文件在白俄羅斯和比利時不在一個文件中。 – jdk2588

+0

是的,正如我所提到的,您需要先創建一個包含國家第一個字母的單獨列。然後在該列上使用'partitionBy' – Shaido