使用Spark

时间:2018-09-12 12:31:35

标签: json scala apache-spark

在过去的几个小时中,我试图使用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)

1 个答案:

答案 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)