在过去的几个小时中,我试图使用Apache Spark将JSON文件转换为Scala case class
。
JSON具有以下结构:
{
"12": {
"wordA": 1,
"wordB": 2,
"wordC": 3
},
"13": {
"wordX": 10,
"wordY": 12,
"wordZ": 15
}
}
首次尝试:设置构建模式
我试图人为地构建我的模式:
val schema = new StructType()
.add("",MapType(StringType, new StructType()
.add("", StringType)
.add("", IntegerType)))
val df = session.read
.option("multiline",true)
.option("mode", "PERMISSIVE")
.schema(schema)
.json(filePath)
df.show()
但这显然是不对的,因为我必须提供字段名称。
第二次尝试:映射到案例类
我还尝试创建case class
es,这有点优雅:
case class KeywordData (keywordsByCode: Map[String, WordAndWeight])
case class WordAndWeight (word: String, weight: Int)
问题:
但是无论如何,df.show()显示:
+----+
| |
+----+
|null|
+----+
由于我的列没有修复名称,因此JSON结构不易于操作。有想法吗?
预期结果
以12和13为键,以List [wordA,... wordC]分别以List [wordX,...,wordZ]作为值的映射
编辑:地图Map 使用案例类
case class WordAndWeight(code: Map[String, Map[String, Integer]])
它给我以下错误:
+-------+----------+
| 12| 13|
+-------+----------+
|[1,2,3]|[10,12,15]|
+-------+----------+
cannot resolve '`code`' given input columns: [12, 13];
org.apache.spark.sql.AnalysisException: cannot resolve '`code`' given input columns: [12, 13];
at org.apache.spark.sql.catalyst.analysis.package$AnalysisErrorAt.failAnalysis(package.scala:42)
答案 0 :(得分:1)
您尝试定义以MapType为根类型的架构。换句话说,您希望每条线都是地图。 AFAIK Spark不支持MapType作为根类型。它仅支持StructType作为根类型。
通过案例类和反射定义类型时,如下所示:
val schema = ScalaReflection.schemaFor[KeywordData].dataType.asInstanceOf[StructType]
您将StructType作为根类型:
root
|-- keywordsByCode: map (nullable = true)
| |-- key: string
| |-- value: struct (valueContainsNull = true)
| | |-- word: string (nullable = true)
| | |-- weight: integer (nullable = true)
这意味着Spark将使用称为keywordsByCode
的一列创建DataFrame。
它将期望像这样的JSON
{"keywordsByCode":{"12":{"wordA":1,"wordB":2,"wordC":3},"13":{"wordX":10,"wordY":12,"wordZ":15}}}
您需要修改JSON或读取文本等文件,然后将每一行解析为JSON。
更新
我没有再发现一个错误,您的案例类应该像这样:
case class KeywordData (keywordsByCode: Map[String, Map[String, Int]])
因为您的JSON嵌套了MapType。因此该架构将如下所示:
root
|-- keywordsByCode: map (nullable = true)
| |-- key: string
| |-- value: map (valueContainsNull = true)
| | |-- key: string
| | |-- value: integer (valueContainsNull = true)
我的测试代码:
val df = spark.read
.option("multiline",true)
.option("mode", "PERMISSIVE")
.schema(ScalaReflection.schemaFor[KeywordData].dataType.asInstanceOf[StructType])
.json("test.json")
df.printSchema()
df.explain(true)
df.show(10)