【问题标题】:Convert all the columns of a spark dataframe into a json format and then include the json formatted data as a column in another/parent dataframe将 spark 数据帧的所有列转换为 json 格式,然后将 json 格式的数据作为列包含在另一个/父数据帧中
【发布时间】:2020-06-04 14:24:15
【问题描述】:

使用 df.toJSON 将数据帧(比如子数据帧)转换为 json

json 转换后的架构如下所示:

root
 |-- value: string (nullable = true)

我使用以下建议将子数据框放入中间父架构/数据框:

scala> parentDF.toJSON.select(struct($"value").as("data")).printSchema
root
 |-- data: struct (nullable = false)
 |    |-- value: string (nullable = true)

现在我仍然需要进一步构建 parentDF 架构以使其看起来像:

root
 |-- id
 |-- version 
 |-- data: struct (nullable = false)
 |    |-- value: string (nullable = true)

Q1) 如何使用 value 中的 id 构建 id 列(即 value.id 需要表示为 id)

Q2)我需要从不同的数据框(比如 versionDF)中获取版本,其中版本是一个常量(在所有列中)。我是否从此 versionDF 中获取一行以读取 version 列的值,然后将其填充为 parentDF 中的文字?

请帮助解决这方面的任何代码 sn-ps。

【问题讨论】:

  • 你能添加 parentdf 架构吗?并添加预期输出

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


【解决方案1】:

select 语句中使用to_json 而不是toJSON 并选择所需的列以及to_json 函数。

检查下面的代码。

val version =  // Get version value from versionDF
parentDF.select($"id",struct(to_json(struct($"*")).as("value")).as("data"),lit(version).as("version"))

scala> parentDF.select($"id",struct(to_json(struct($"*")).as("value")).as("data"),lit(version).as("version")).printSchema
root
 |-- id: integer (nullable = false)
 |-- data: struct (nullable = false)
 |    |-- value: string (nullable = true)
 |-- version: double (nullable = false)

更新

scala> df.select($"id",to_json(struct(struct($"*").as("value"))).as("data"),lit(version).as("version")).printSchema
root
 |-- id: integer (nullable = false)
 |-- data: string (nullable = true)
 |-- version: integer (nullable = false)


scala> df.select($"id",to_json(struct(struct($"*").as("value"))).as("data"),lit(version).as("version")).show(false)
+---+------------------------------------------+-------+
|id |data                                      |version|
+---+------------------------------------------+-------+
|1  |{"value":{"id":1,"col1":"a1","col2":"b1"}}|1      |
|2  |{"value":{"id":2,"col1":"a2","col2":"b2"}}|1      |
|3  |{"value":{"id":3,"col1":"a3","col2":"b3"}}|1      |
+---+------------------------------------------+-------+

Update-1

scala> df.select($"id",to_json(struct($"*").as("value")).as("data"),lit(version).as("version")).printSchema
root
 |-- id: integer (nullable = false)
 |-- data: string (nullable = true)
 |-- version: integer (nullable = false)


scala> df.select($"id",to_json(struct($"*").as("value")).as("data"),lit(version).as("version")).show(false)
+---+--------------------------------+-------+
|id |data                            |version|
+---+--------------------------------+-------+
|1  |{"id":1,"col1":"a1","col2":"b1"}|1      |
|2  |{"id":2,"col1":"a2","col2":"b2"}|1      |
|3  |{"id":3,"col1":"a3","col2":"b3"}|1      |
+---+--------------------------------+-------+

【讨论】:

  • 这种方法很好。但是,当我访问“数据”时,我看到了一个 jsonarray 附件。需要数据作为 jsonobject。是否有代码调整可以实现相同的效果。
  • 你能输出它是怎么来的和你想要的吗?
  • 当前数据内容如下所示:[{"id":1,"col1":"a1","col2":"b1"}] 预期数据格式:{"id" :1,"col1":"a1","col2":"b1"} 注意:后一个没有 [ ] 外壳 - 这是它的预期(jsonobject)。感谢您的帮助。
  • 您想要对象的任何具体原因,试图理解问题??
  • 这个程序更多的是一个要求,并且默认情况下以jsonobject格式表示数据是很自然的(我认为)。 jsonarray 更像是一个 jsonobjects 的集合——这里的 'data' 字段只是一个 json 对象。
【解决方案2】:

试试这个:

scala> val versionDF = List((1.0)).toDF("version")
versionDF: org.apache.spark.sql.DataFrame = [version: double]

scala> versionDF.show
+-------+
|version|
+-------+
|    1.0|
+-------+


scala> val version = versionDF.first.get(0)
version: Any = 1.0

scala>

scala> val childDF = List((1,"a1","b1"),(2,"a2","b2"),(3,"a3","b3")).toDF("id","col1","col2")
childDF: org.apache.spark.sql.DataFrame = [id: int, col1: string ... 1 more field]

scala> childDF.show
+---+----+----+
| id|col1|col2|
+---+----+----+
|  1|  a1|  b1|
|  2|  a2|  b2|
|  3|  a3|  b3|
+---+----+----+


scala>

scala> val parentDF =  childDF.toJSON.select(struct($"value").as("data")).withColumn("id",from_json($"data.value",childDF.schema).getItem("id")).withColumn("version",lit(version))
parentDF: org.apache.spark.sql.DataFrame = [data: struct<value: string>, id: int ... 1 more field]

scala> parentDF.printSchema
root
 |-- data: struct (nullable = false)
 |    |-- value: string (nullable = true)
 |-- id: integer (nullable = true)
 |-- version: double (nullable = false)

scala> parentDF.show(false)
+----------------------------------+---+-------+
|data                              |id |version|
+----------------------------------+---+-------+
|[{"id":1,"col1":"a1","col2":"b1"}]|1  |1.0    |
|[{"id":2,"col1":"a2","col2":"b2"}]|2  |1.0    |
|[{"id":3,"col1":"a3","col2":"b3"}]|3  |1.0    |
+----------------------------------+---+-------+

【讨论】:

  • 感谢您的建议。为什么当我们执行 toJSON 或 to_json 时,数据会反映为 jsonarray。我们可以通过任何方式获取表示 jsonobject 的“数据”吗?
  • struct 函数使它看起来像数组。例如'childDF.select(struct(lit("col1val"),lit("col2val")).as("structColumn")).show |结构列| +-----------------+ |[col1val, col2val]|'如果您不想要它,只需在下面使用:childDF.toJSON.withColumnRenamed("value","data").show(false) +--------------------------------+ |data | +--------------------------------+ |{"id":1,"col1":"a1","col2":"b1"}| |{"id":2,"col1":"a2","col2":"b2"}| |{"id":3,"col1":"a3","col2":"b3"}| +--------------------------------+
猜你喜欢
  • 2023-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-04
  • 2019-12-21
  • 2022-12-05
  • 2020-12-09
  • 1970-01-01
相关资源
最近更新 更多