[英]Spark UDF: How to write a UDF on each row to extract a specific value in a nested struct?
我在 Java 中使用 Spark 來處理 XML 文件。 databricks 中的 spark-xml 包用於將 xml 文件讀入數據幀。
示例 xml 文件是:
<RowTag>
<id>1</id>
<name>john</name>
<expenses>
<travel>
<details>
<date>20191203</date>
<amount>400</amount>
</details>
</travel>
</expenses>
</RowTag>
<RowTag>
<id>2</id>
<name>joe</name>
<expenses>
<food>
<details>
<date>20191204</date>
<amount>500</amount>
</details>
</food>
</expenses>
</RowTag>
結果 spark Dataset<Row> df
如下所示,每一行代表一個 xml 文件。
+--+------+----------------+
|id| name |expenses |
+---------+----------------+
|1 | john |[[20191203,400]]|
|2 | joe |[[20191204,500]]|
+--+------+----------------+
df.printSchema();
顯示如下:
root
|-- id: int(nullable = true)
|-- name: string(nullable = true)
|-- expenses: struct (nullable = true)
| |-- travel: struct (nullable = true)
| | |-- details: struct (nullable = true)
| | | |-- date: string (nullable = true)
| | | |-- amount: int (nullable = true)
| |-- food: struct (nullable = true)
| | |-- details: struct (nullable = true)
| | | |-- date: string (nullable = true)
| | | |-- amount: int (nullable = true)
所需的輸出數據幀是這樣的:
+--+------+-------------+
|id| name |expenses_date|
+---------+-------------+
|1 | john |20191203 |
|2 | joe |20191204 |
+--+------+-------------+
基本上我想要一個通用的解決方案來從具有以下結構的 xml 中獲取日期,其中只有標簽<X>
會有所不同。
<RowTag>
<id>1</id>
<name>john</name>
<expenses>
**<X>**
<details>
<date>20191203</date>
<amount>400</amount>
</details>
**</X>**
</expenses>
</RowTag>
我嘗試過的:
spark.udf().register("getDate",(UDF1 <Row, String>) (Row row) -> {
return row.getStruct(0).getStruct(0).getAs("date").toString();
}, DataTypes.StringType);
df.select(callUDF("getDate",df.col("expenses")).as("expenses_date")).show();
但它不起作用,因為 row.getStruct(0) 路由到<travel>
,但對於 row joe, <expenses>
下沒有<travel>
標簽,所以它返回了java.lang.NullPointerException
。 我想要的是一個通用的解決方案,對於每一行,它可以自動獲取下一個標簽名稱,例如row.getStruct(0)
路由到<travel>
行 john 和<food>
行 joe。
所以我的問題是:我應該如何重新制定我的 UDF 來實現這一目標?
提前致謝!! :)
spark-xml包允許您直接在選擇表達式中訪問嵌套字段。 你為什么要尋找UDF?
df.selectExpr("id", "name", "COALESCE(`expenses`.`food`.`details`.`date`, `expenses`.`travel`.`details`.`date`) AS expenses_date" ).show()
輸出:
+---+----+-------------+
| id|name|expenses_date|
+---+----+-------------+
| 1|john| 20191203|
| 2| joe| 20191204|
+---+----+-------------+
編輯
如果唯一發生變化的標簽是expenses
結構之后的標簽,那么您可以搜索expenses
下的所有字段,然后coalesce
列: expenses.X.details.date
。 在 Spark 中是這樣的:
val expenses_fields = df.select(col("expenses.*")).columns
val date_cols = expenses_fields.map(f => col(s"`expenses`.`$f`.`details`.`date`"))
df.select(col("id"), col("name"), coalesce(date_cols: _*).alias("expenses_date")).show()
不過,您不需要使用 UDF!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.