我使用Spark 1.6和Scala。
我正在寻找here,但我没有找到明确的答案
我有一个大文件,在过滤了包含一些版权的第一行后,我想获取标题(104个字段)并将其转换为StructType
模式。
我正在考虑使用类扩展Product
特征来定义Dataframe
的模式,然后根据该模式将其转换为Dataframe
。
最好的方法是什么。
这是我文件中的一个示例:
text (06.07.03.216) COPYRIGHT © skdjh 2000-2016
text 160614_54554.vf Database 53643_csc Interface 574 zn 65
Start Date 14/06/2016 00:00:00:000
End Date 14/06/2016 00:14:59:999
State "s23"
cin. Nb Start End Event Con. Duration IMSI
32055680 16/09/2010 16:59:59:245 16/09/2016 17:00:00:000 xxxxxxxxxxxxx
32055680 16/09/2010 16:59:59:245 16/09/2016 17:00:00:000 xxxxxxxxxxxxx
32055680 16/09/2010 16:59:59:245 16/09/2016 17:00:00:000 xxxxxxxxxxxxx
32055680 16/09/2010 16:59:59:245 16/09/2016 17:00:00:000 xxxxxxxxxxxxx
32055680 16/09/2010 16:59:59:245 16/09/2016 17:00:00:000 xxxxxxxxxxxxx
T想要像这个架构一样将它转换为SparkSQL
----------------------------------------------------------------------------------------
| cin_Nb | Start | End | Event | Con_Duration | IMSI |
| ----------------------------------------------------------------------------------------|
| 32055680 | 16/09/2010 | 16:59:59:245 | 16/09/2016 | 17:00:00:000 | xxxxx |
| 32055680 | 16/09/2010 | 16:59:59:245 | 16/09/2016 | 17:00:00:000 | xxxxx |
| 32055680 | 16/09/2010 | 16:59:59:245 | 16/09/2016 | 17:00:00:000 | xxxxx |
| 20556800 | 16/09/2010 | 16:59:59:245 | 16/09/2016 | 17:00:00:000 | xxxxx |
| 32055680 | 16/09/2010 | 16:59:59:245 | 16/09/2016 | 17:00:00:000 | xxxxx |
----------------------------------------------------------------------------------------
答案 0 :(得分:0)
不幸的是,您无法使用案例类或StructType架构!原因是scala不支持超过22个部分的元组,这两种方法都在幕后使用元组。由于您有超过22列,该方法不起作用。
然而,你仍然可以做到这一点,它只是不太好:)你需要做的是将它转换为单列数据帧,并调用列有意义的像“原始”
val df = rdd.toDF("raw")
接下来,您需要定义一个函数来为任何给定列提取所需的列:
val extractData(idx: Long) = udf[String, String, Int](raw => ???)
现在,您需要使用此功能附加所需的每个列。
val columns = yourColumnNamesList.zipWithIndex
val df2 = columns.foldLeft(df){case (acc,(cname,cid)) => acc.withColumn(cname, extractData(cid)($"raw")}
尽管在执行foldLeft时看起来有点可怕,但是如果你看一下执行计划器创建的计划,那么spark就足够聪明,可以将所有这些内容压缩成一个映射步骤,并且吞吐量比你预期的要好。
最后,您可以删除原始数据,因为不再需要它。
df2.drop("raw")
可替换地!
如果您的数据在文件系统上采用分隔格式,那么您应该查看DataBricks csv解析器,该解析器也适用于1.6: - )
答案 1 :(得分:0)
你可以使用zipwithindex而不是过滤第一行 你可以使用一个类检查标题
class convert( var cin_Nb:String, var start:String, var end:String,
var event:String, var duration:String, var zed:String,......)extends Product with Serializable {
def canEqual(that: Any) = that.isInstanceOf[convert]
def productArity = 104
def productElement(idx: Int) = idx match {
case 0 => cin_Nb;case 1 => start;case 2 => end;
case 3 => event;case 4 => duration;case 5 => zed;
..........
}
}
并使用此结构将rdd转换为dataframe