Spark:正确的架构以将JSON作为DataFrame加载

时间:2018-09-11 22:49:04

标签: json apache-spark apache-spark-sql schema

我有一个类似

的JSON
{ 1234 : "blah1", 9807: "blah2", 467: "blah_k", ...}

已写入压缩文件。它是一个ID空间到另一个ID空间的映射,其中键是int,值是string

我想在Spark中将其加载为DataFrame

我将其加载为

val df = spark.read.format("json").load("my_id_file.json.gz")

默认情况下,Spark为其加载了一个类似如下的模式

 |-- 1234: string (nullable = true)
 |-- 9807: string (nullable = true)
 |-- 467: string (nullable = true)

相反,我希望我的DataFrame看起来像

+----+------+
|id1 |id2   |
+----+------+
|1234|blah1 |
|9007|blah2 |
|467 |blah_k|    
+----+------+

所以,我尝试了以下方法。

import org.apache.spark.sql.types._
val idMapSchema = StructType(Array(StructField("id1", IntegerType, true), StructField("id2", StringType, true)))

val df = spark.read.format("json").schema(idMapSchema).load("my_id_file.json.gz")

但是,加载的数据帧看起来像

scala> df.show
+----+----+
|id1 |id2 |
+----+----+
|null|null|
+----+----+

如何指定解决方案?是否有“纯”数据框方法(无需创建RDD然后创建数据框)?

1 个答案:

答案 0 :(得分:0)

一种实现此目的的方法是将输入文件读取为textFile,并在map()中应用解析逻辑,然后将结果转换为数据帧

import scala.collection.JavaConversions._
import scala.collection.mutable.ListBuffer

val rdd = sparkSession.sparkContext.textFile("my_input_file_path")
  .map(row => {
    val list = new ListBuffer[String]()
    val inputJson = new JSONObject(row)

    for (key <- inputJson.keySet()) {
      val resultJson = new JSONObject()
      resultJson.put("col1", key)
      resultJson.put("col2", inputJson.get(key))

      list += resultJson.toString()
    }

    list
  }).flatMap(row => row)

val df = sparkSession.read.json(rdd)
df.printSchema()
df.show(false)

输出:

root
 |-- col1: string (nullable = true)
 |-- col2: string (nullable = true)

+----+------+
|col1|col2  |
+----+------+
|1234|blah1 |
|467 |blah_k|
|9807|blah2 |
+----+------+