如何使用嵌套元素将数据集从CSV转换为JSON?

时间:2017-12-15 13:40:58

标签: scala apache-spark apache-spark-sql

我有以下csv文件:

LID,Name,age,CID
122,David,29,ECB4
122,Frank,31,ECB4
567,David,29,ECB4
567,Daniel,35,ECB4

我想先通过CID对数据进行分组,然后再将其分类为LID,并将它们保存为json,以便它们具有这种结构:

{  
    "CID": "ECB4",
    "logs":[ {
            "LID":122,
            "body":[{
                   "name":"David",
                   "age":29
                  },
                  {
                   "name":"Frank",
                   "age":31
                  }
                 ]
            },
             "LID":567,
              "body":[{
                   "name":"David",
                   "age":29
                  },
                  {
                   "name":"Daniel",
                   "age":35
                  }
                 ]

              }

         ] 
} 

我已经定义了一个模式并将数据加载到数据框中:

 sparkSession.sqlContext.read.format("csv")
  .option("delimiter",",").schema(someSchema).load("...")

但我不知道如何按照想要的方式对数据帧进行分组。 groupBy函数返回一个我不能保存为json的RelationalGroupedDataset。 sql查询希望我在分组后使用聚合。

我将不胜感激。

1 个答案:

答案 0 :(得分:3)

groupBy仅定义您可以在以后用于运行聚合的分组。为了以JSON格式保存结果,您必须定义将对分组起作用的最终操作。

  

groupBy(col1:String,cols:String *):RelationalGroupedDataset 使用指定的列对数据集进行分组,以便我们可以对它们运行聚合。

     

有关所有可用的聚合函数,请参阅RelationalGroupedDataset

换句话说,您必须使用RelationalGroupedDataset界面执行聚合,您可以从中使用最通用的agg运算符。

  

agg(expr:Column,exprs:Column *):DataFrame 通过指定一系列聚合列来计算聚合。

如果我没有弄错(通过查看输出JSON文件),您可以groupBy收集每个LID的名称和年龄字段。

您应该执行以下操作:

// Load your dataset
val cids = spark.read.option("header", true).csv("cids.csv")
scala> cids.show
+---+------+---+----+
|LID|  Name|age| CID|
+---+------+---+----+
|122| David| 29|ECB4|
|122| Frank| 31|ECB4|
|567| David| 29|ECB4|
|567|Daniel| 35|ECB4|
+---+------+---+----+

使用数据集时,您必须先structnameage参与聚合。

val name_ages = cids.withColumn("name_age", struct("name", "age"))
scala> name_ages.show
+---+------+---+----+-----------+
|LID|  Name|age| CID|   name_age|
+---+------+---+----+-----------+
|122| David| 29|ECB4| [David,29]|
|122| Frank| 31|ECB4| [Frank,31]|
|567| David| 29|ECB4| [David,29]|
|567|Daniel| 35|ECB4|[Daniel,35]|
+---+------+---+----+-----------+

现在,它应该相当简单。

val logs = name_ages.groupBy("CID", "LID")
  .agg(collect_list("name_age") as "logs") // <-- that's the missing piece in the puzzle
scala> logs.show(truncate = false)
+----+---+-------------------------+
|CID |LID|logs                     |
+----+---+-------------------------+
|ECB4|122|[[David,29], [Frank,31]] |
|ECB4|567|[[David,29], [Daniel,35]]|
+----+---+-------------------------+

远离...... (作为家庭练习:))

提示:您可能希望再次使用struct