如何访问数组类型值并在两个不同的列中设置火花?
Posted
技术标签:
【中文标题】如何访问数组类型值并在两个不同的列中设置火花?【英文标题】:How to access array type value and set in two different columns spark? 【发布时间】:2020-09-21 13:30:59 【问题描述】:我正在学习 Spark,我有下面的 xml,我想从中读取 2 个值并创建两个不同的列
<appRoot>
<applist>
<app type="test">
<code>8.52544</code>
</app>
<app type="dev">
<code>8.52537</code>
</app>
</applist>
</appRoot>
我想要
如果 type="test" 那么它应该在新列“app_test”中设置值(即 8.52544)和
如果 type="dev" 那么它应该在新列 "app_dev" 中设置值(即 8.52537)
我在下面尝试过
df.select(
functions.when($"applist.app._type" === "test", $"applist.app.code").as("app_test"),
functions.when($"applist.app._type" === "dev", $"applist.app.code").as("app_dev"))
但它会返回
app_test with value [8.52544, 8.52537]
app_dev with value [8.52544, 8.52537]
在为列设置值时如何区分?
更新:
val df = spark.read
.format("com.databricks.spark.xml")
.option("rootTag", "appRoot")
.option("rowTag", "applist")
.load("test.xml")
df.printSchema()
root
|-- app: array (nullable = true)
| |-- element: struct (containsNull = true)
| | |-- _type: string (nullable = true)
| | |-- code: double (nullable = true)
【问题讨论】:
@vaquarkhan 仅供参考,我没有否决你的答案,如果你检查我的第一个问题版本,它总是从数组类型列中获取值到两个单独的列中。 我很高兴你得到你的答案:) 【参考方案1】:使用map_from_entries 可以将数组转换为使用_type
作为键和code
作为值的映射。然后可以使用地图创建两个新列。
val df = spark.read.format("com.databricks.spark.xml")
.option("rootTag", "appRoot").option("rowTag","applist")
.load(...)
df.withColumn("map", map_from_entries('app))
.withColumn("app_test", 'map("test"))
.withColumn("app_dev", 'map("dev"))
.drop('map)
.show(false)
打印(带有一些额外的测试数据)
+--------------------------------------------+--------+-------+
|app |app_test|app_dev|
+--------------------------------------------+--------+-------+
|[[test, 8.52544], [dev, 8.52537], [x, 1.23]]|8.52544 |8.52537|
|[[test, 1.2], [dev, 3.4], [X, 9.9]] |1.2 |3.4 |
|[[dev, -5.6], [Z, -12.9]] |null |-5.6 |
+--------------------------------------------+--------+-------+
【讨论】:
您在 rootTag 和 rowTag 中指定了什么来读取 XML?由于将 rowTag 指定为 applist,即使 xml 包含多个应用程序标签,也只会获得单行输入。 @ShreyJakhmola 我已经添加了加载 xml 的代码。在我的示例 xml 文件 here 中,我添加了多个applist
条目以生成额外的行。但是,如果您不需要这些额外的行,您可以节省地忽略它们【参考方案2】:
您可以这样做:
将数据读入数据框。
val df = spark.read.format("com.databricks.spark.xml").option("rootTag", "appRoot").option("rowTag","applist").load("/home/shrey/Downloads/mydoc.xml")
df.printSchema()
df.show()
最后可以通过爆炸数组的方式在when条件中选择合适的列:
df.select(explode($"app").as("app")).select(functions.when($"app._type" === "test", $"app.code").as("app_test"),functions.when($"app._type" === "dev", $"app.code").as("app_dev")).show(false)
如果你想在一行中输出,你可以使用 max() 函数来聚合它。
df.select(explode($"app").as("app")).select(functions.when($"app._type" === "test", $"app.code").as("app_test"),functions.when($"app._type" === "dev", $"app.code").as("app_dev")).agg(max($"app_test").as("app_test"),max($"app_dev").as("app_dev")).show(false)
【讨论】:
请检查我更新的 xml,我添加了一个根标签。所需的字段,即“app”是数组类型以上是关于如何访问数组类型值并在两个不同的列中设置火花?的主要内容,如果未能解决你的问题,请参考以下文章