TL; DR :当我将一个Spark DataFrame
转储为json时,我总是得到像
{"key1": "v11", "key2": "v21"}
{"key1": "v12", "key2": "v22"}
{"key1": "v13", "key2": "v23"}
这是无效的json。我可以手动编辑转储文件以获得我可以解析的内容:
[
{"key1": "v11", "key2": "v21"},
{"key1": "v12", "key2": "v22"},
{"key1": "v13", "key2": "v23"}
]
但我很确定我错过了一些可以让我避免这种手动编辑的东西。我现在不知道。
更多详情:
我有一个org.apache.spark.sql.DataFrame
,我尝试使用以下代码将其转储到json:
myDataFrame.write.json("file.json")
我也尝试过:
myDataFrame.toJSON.saveAsTextFile("file.json")
在这两种情况下,它最终都会正确地转储每一行,但它缺少行之间的分隔逗号,以及方括号。 因此,当我随后尝试解析此文件时,我使用的解析器会侮辱我然后失败。
我将很高兴知道如何转储有效的json。 (阅读DataFrameWriter的文档没有给我提供任何有趣的提示。)
答案 0 :(得分:1)
这是预期的输出。 Spark使用JSON Lines之类的格式有很多原因:
Row
是一个映射到JSON对象而不是数组的结构。您可以通过几种方式创建所需的输出,但它始终与上述之一冲突。
例如,您可以为每个分区编写一个JSON 文档:
import org.apache.spark.sql.functions._
df
.groupBy(spark_partition_id)
.agg(collect_list(struct(df.columns map col: _*)).alias("data"))
.select($"data")
.write
.json(output_path)
您可以在repartition(1)
前面添加一个输出文件,但这不是您想要做的事情,除非数据非常小。
1.6替代方案将是glom
import org.apache.spark.sql.Row
import org.apache.spark.sql.types._
val newSchema = StructType(Seq(StructField("data", ArrayType(df.schema))))
sqlContext.createDataFrame(
df.rdd.glom.flatMap(a => if(a.isEmpty) Seq() else Seq(Row(a))),
newSchema
)