我有以下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查询希望我在分组后使用聚合。
我将不胜感激。
答案 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|
+---+------+---+----+
使用数据集时,您必须先struct
列name
和age
参与聚合。
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
。