Scala 在不同列的spark中读取csv文件
我想使用Scala将csv文件读入spark中的数据帧。 我的csv文件有第一条记录,其中有三列,其余记录有五列。我的csv文件没有列名。我在这里提到的是为了理解Scala 在不同列的spark中读取csv文件,scala,csv,apache-spark,Scala,Csv,Apache Spark,我想使用Scala将csv文件读入spark中的数据帧。 我的csv文件有第一条记录,其中有三列,其余记录有五列。我的csv文件没有列名。我在这里提到的是为了理解 Ex: I'dtype date recordsCount 0 13-02-2015 300 I'dtype date type location. locationCode 1 13-02-2015. R. U
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
我的问题是如何将此文件读入dataframe,因为第一行和其余行具有不同的列。
我尝试的解决方案是将文件读取为rdd,过滤掉头记录,然后将剩余记录转换为数据帧。
有没有更好的解决办法?请帮帮我,这有点麻烦,但这里有一个忽略文件第一行的解决方案
val cols=Array(“数据类型”、“日期”、“类型”、“位置”、“位置代码”)
val schema=new StructType(cols.map(n=>StructField(n,StringType,true)))
spark.read
.schema(schema)//我们指定模式
.option(“header”,true)//并告诉spark有一个header
.csv(“路径/文件.csv”)
第一行是标题,但指定了架构。因此,第一行被忽略。您可以将文件作为原始文本加载,然后使用case类、
实例或
实例,以及模式匹配来排序要放在哪里。下面是一个例子
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()
使用以下简单tsv进行测试:
col1 col2 col3
0 sfd 300
1 asfd 400
col1 col2 col4 col5 col6
2 pljdsfn R USA Us
3 sad T London Lon
它给出了输出
+---+----+---+
| c1| c2| c3|
+---+----+---+
| 0| sfd|300|
| 1|asfd|400|
+---+----+---+
+---+-------+-------+------+---+
| c1| c2|c5_col3| c4| c5|
+---+-------+-------+------+---+
| 2|pljdsfn| R| USA| Us|
| 3| sad| T|London|Lon|
+---+-------+-------+------+---+
为了简单起见,我忽略了日期格式,只是将这些字段存储为字符串。然而,添加一个日期解析器来获得一个合适的列类型不会复杂得多
同样,我依赖解析失败来指示标题行。如果解析不会失败,或者必须进行更复杂的确定,则可以替换不同的逻辑。类似地,需要更复杂的逻辑来区分相同长度的不同记录类型,或者可能包含(转义)拆分字符的记录类型最后两列中的任何一列都可以为空吗?看起来除了有两个不同的列长度外,还有不同的列,第三列为recordsCount或type。这让事情变得更复杂了,可能应该在你们的问题中注意到。我不想忽略标题。我需要进一步的处理标题。比你这么多的详细答案。