我必须从hdfs中读取一个csv文件,然后我需要应用将每一列都填充到固定宽度的逻辑,然后仅需要将其存储为hdfs作为固定宽度文件。没有任何其他形式的示例csv或镶木地板。
如果我将hdfs的输入读取为csv,如下例所示:
Name, age, phonenumber
A, 25,9900999999
B, 26,7654890234
C, 27,5643217897
然后我需要对固定宽度的每一列应用逻辑,例如第一列宽度应设置为15,第二列3,第三列应为10
在hdfs中输出应如下所示。
Name age phonenumber
A 25 9900999999
B 26 7654890234
C 27 5643217897
然后,我需要将固定宽度数据作为固定宽度文件格式写入到hdfs中。
答案 0 :(得分:0)
您的样本输出似乎带有分隔符,因为年龄和电话号码之间有空格。我猜想这是一个制表符分隔符,在这种情况下,您可以阅读csv并用spark.save.option("sep","\t").csv("filename")
但是如果您所写的内容正确,则可以通过以下方式获得它:
import org.apache.spark.sql.functions.rpad
val df=spark.read.option("header","false").csv("...")
val out= df.select(rpad($"_c0",15," "),
rpad($"_c1",3," "),
rpad($"_c2",10," "))
out.map(_.mkString("")).write.text("filename")
请注意,我将标头设置为false,以便也将其填充
答案 1 :(得分:0)
如果已经使用了inferSchema,则需要将所有列都强制转换为字符串。 将长度映射到df.columns,以便可以动态处理。 检查一下:
scala> val df = Seq(("A", 25,9900999999L),("B", 26,7654890234L),("C", 27,5643217897L)).toDF("Name","age","phonenumber")
df: org.apache.spark.sql.DataFrame = [Name: string, age: int ... 1 more field]
scala> df.show(false)
+----+---+-----------+
|Name|age|phonenumber|
+----+---+-----------+
|A |25 |9900999999 |
|B |26 |7654890234 |
|C |27 |5643217897 |
+----+---+-----------+
scala> val widths = Array(5,3,10)
widths: Array[Int] = Array(5, 3, 10)
scala> df.columns.zip(widths)
res235: Array[(String, Int)] = Array((Name,5), (age,3), (phonenumber,10))
scala> df.columns.zip(widths).foldLeft(df){ (acc,x) => acc.withColumn(x._1,rpad( trim(col(x._1).cast("string")),x._2," ")) }.show(false)
+-----+---+-----------+
|Name |age|phonenumber|
+-----+---+-----------+
|A |25 |9900999999 |
|B |26 |7654890234 |
|C |27 |5643217897 |
+-----+---+-----------+
要验证填充。
scala> df.columns.zip(widths).foldLeft(df){ (acc,x) => acc.withColumn(x._1,rpad( trim(col(x._1).cast("string")),x._2,"-")) }.show(false)
+-----+---+-----------+
|Name |age|phonenumber|
+-----+---+-----------+
|A----|25-|9900999999 |
|B----|26-|7654890234 |
|C----|27-|5643217897 |
+-----+---+-----------+
scala>