如何设置Spark CSV输出的数值格式?调整Double类型输出格式
解决Spark CSV输出Double类型数据的格式问题
这个问题我之前也碰到过,Spark默认确实会把大数Double转成科学计数法输出到CSV里,要改成你需要的1000000000000.00这种固定格式,主要有两种实用的办法,我给你详细说说:
方法一:直接在SQL中用格式化函数转换
如果你的数据是通过SQL查询生成的,可以直接用Spark SQL的format_string函数,指定小数位数来格式化Double值,这样输出的就是符合要求的字符串格式:
val t = spark.sql("SELECT format_string('%.2f', cast(1000000000000 as double)) as aNum") t.write.csv("WXYZ")
这里'%.2f'是格式化模板,%.2f表示保留两位小数的浮点数格式,这样输出的结果就是1000000000000.00,不会出现科学计数法。
注意:如果用
format_number函数的话,会自动添加千分位分隔符(比如输出1,000,000,000,000.00),如果你不需要这个分隔符,就用format_string更合适。
方法二:自定义UDF批量处理所有Double列
如果你的DataFrame里有很多Double类型的列,一个个改SQL太麻烦,可以自定义一个UDF(用户自定义函数),批量处理所有Double列:
- 首先定义格式化Double的UDF,同时处理可能的null值:
import org.apache.spark.sql.functions._ import org.apache.spark.sql.types.DoubleType // 定义UDF,处理Double类型,保留两位小数,同时兼容null值 val formatDoubleUdf = udf((num: Option[Double]) => { num.map(n => f"$n%.2f").orElse(None) })
- 然后自动识别DataFrame中所有的Double类型列,批量应用UDF替换原列:
// 获取所有Double类型的列名 val doubleColumnNames = df.schema.fields .filter(_.dataType == DoubleType) .map(_.name) // 遍历所有Double列,用UDF格式化后替换原列 val formattedDF = doubleColumnNames.foldLeft(df) { (tempDF, colName) => tempDF.withColumn(colName, formatDoubleUdf(col(colName))) } // 写入CSV formattedDF.write.csv("WXYZ")
这样处理后,所有Double列都会被转成保留两位小数的字符串,输出到CSV里就是你想要的格式了。
补充说明
目前Spark的CSV数据源并没有提供全局配置参数来直接设置Double类型的输出格式,所以必须先把Double类型转换为格式化后的字符串,再写入CSV。这种转换不会影响数据的可读性,因为CSV本身就是文本格式,后续读取时如果需要转回数值类型,也可以通过cast函数处理。
内容的提问来源于stack exchange,提问作者Carbon
相关产品推荐
相关产品推荐

