Spark 1.6.3嵌套DataFrame写入JSON时深层属性驼峰格式丢失
我刚踩过一模一样的坑!在Spark 1.6.3里确实会出现这种情况——顶层列的驼峰命名能好好保留,但嵌套结构体里的字段全被转成小写了,折腾了好一阵才搞明白根源和解决办法。
问题原因
Spark 1.6.x版本的JSON数据源(org.apache.spark.sql.json)在处理嵌套结构体时,内部默认会把结构体的字段名转为小写。这是早期版本的一个设计差异:顶层列名直接沿用DataFrame Schema里的定义,但嵌套struct的字段名会经过一层小写转换处理,导致驼峰格式丢失。另外你用的copyMerge只是合并分片文件,不会修改内容,所以问题其实在Spark写入JSON的环节就已经出现了。
解决办法
我当时试了两种可行的方案,都能完整保留所有层级的驼峰格式:
方案1:用toJSON生成JSON字符串再保存
放弃直接调用df.write.json(),先把每行数据转为JSON字符串,再保存为文本文件:
// 将DataFrame转为JSON字符串的RDD val jsonRdd = df.toJSON // 保存为文本文件,此时所有层级的字段名都会保留驼峰格式 jsonRdd.saveAsTextFile(targetPath) // 再用你的copyMerge合并分片文件 FileUtil.copyMerge(fs, srcPath, fs, dstFile, deleteSource, configuration, null)
这个方法的核心是toJSON会严格按照DataFrame的Schema生成完整的JSON字符串,不会对嵌套字段名做任何大小写转换,完美保留原始的驼峰命名,操作也最简单。
方案2:自定义JSON序列化配置(进阶)
如果需要更精细的序列化控制,可以修改Spark的Jackson配置来禁用字段名的小写转换。在Spark 1.6中,你可以通过设置spark.sql.jsonGenerator相关参数,或者自定义JSONOptions来调整序列化行为。不过这个方法需要修改Spark配置或自定义数据源,相对复杂,如果你只是需要保留驼峰名,方案1完全够用。
亲测这两种方法在Spark 1.6.3环境下都有效,你可以根据自己的场景选择合适的方案。
内容的提问来源于stack exchange,提问作者Ergosum

