我想使用Scala在火花中将csv文件读取到dataframe中。 我的csv文件具有包含三列的第一条记录,其余记录具有5列。我的csv文件没有列名。我提到这是为了理解
Ex:
I'dtype date recordsCount
0 13-02-2015 300
I'dtype date type location. locationCode
1 13-02-2015. R. USA. Us
1. 13-02-2015. T. London. Lon
我的问题是我将如何将此文件读入数据帧,因为第一行和其余行具有不同的列。 我尝试的解决方案是将文件读取为rdd并过滤出标头记录,然后将剩余的记录转换为dataframe。 有更好的解决方案吗?请帮助我
答案 0 :(得分:1)
有点hack,但这是一种忽略文件第一行的解决方案。
val cols = Array("dtype", "date", "type", "location", "locationCode")
val schema = new StructType(cols.map(n => StructField(n ,StringType, true)))
spark.read
.schema(schema) // we specify the schema
.option("header", true) // and tell spark that there is a header
.csv("path/file.csv")
第一行是标题,但是指定了架构。因此,第一行将被忽略。
答案 1 :(得分:1)
您可以将文件作为原始文本加载,然后使用案例类,if (q1 < 0 || q1 > 100) {
alert("Invalid percentage entered.");
} else if ...
实例和模式匹配来找出问题所在。下面的例子。
Either
通过下面的简单tsv测试:
case class Col3(c1: Int, c2: String, c3: Int)
case class Col5(c1: Int, c2: String, c5_col3: String, c4:String, c5: String)
case class Header(value: String)
type C3 = Either[Header, Col3]
type C5 = Either[Header, Col5]
// assume sqlC & sc created
val path = "tmp.tsv"
val rdd = sc.textFile(path)
val eitherRdd: RDD[Either[C3, C5]] = rdd.map{s =>
val spl = s.split("\t")
spl.length match{
case 3 =>
val res = Try{
Col3(spl(0).toInt, spl(1), spl(2).toInt)
}
res match{
case Success(c3) => Left(Right(c3))
case Failure(_) => Left(Left(Header(s)))
}
case 5 =>
val res = Try{
Col5(spl(0).toInt, spl(1), spl(2), spl(3), spl(4))
}
res match{
case Success(c5) => Right(Right(c5))
case Failure(_) => Right(Left(Header(s)))
}
case _ => throw new Exception("fail")
}
}
val rdd3 = eitherRdd.flatMap(_.left.toOption)
val rdd3Header = rdd3.flatMap(_.left.toOption).collect().head
val df3 = sqlC.createDataFrame(rdd3.flatMap(_.right.toOption))
val rdd5 = eitherRdd.flatMap(_.right.toOption)
val rdd5Header = rdd5.flatMap(_.left.toOption).collect().head
val df5 = sqlC.createDataFrame(rdd5.flatMap(_.right.toOption))
df3.show()
df5.show()
给出输出
col1 col2 col3
0 sfd 300
1 asfd 400
col1 col2 col4 col5 col6
2 pljdsfn R USA Us
3 sad T London Lon
为简单起见,我忽略了日期格式,只是将这些字段存储为字符串。但是,添加日期解析器以获取适当的列类型并不会复杂得多。
同样,我依靠解析失败来指示标题行。如果解析不会失败,或者必须进行更复杂的确定,则可以使用其他逻辑。同样,将需要更复杂的逻辑来区分相同长度的不同记录类型,或者可能包含(转义的)分割字符
答案 2 :(得分:-1)
您可以在阅读时删除这些格式错误的行。
spark.read
.option("mode", "dropMalformed")
...