我正在使用scala将json数据读入spark数据框。 架构如下:
root
|-- metadata: array (nullable = true)
| |-- element: struct (containsNull = true)
| | |-- playerId: string (nullable = true)
| | |-- sources: array (nullable = true)
| | | |-- element: struct (containsNull = true)
| | | | |-- matchId: long (nullable = true)
数据如下:
{ "metadata" : [ { "playerId" : "1234", "sources" : [ { "matchId": 1 } ] }, { "playerId": "1235", "sources": [ { "matchId": 1 } ] } ] }
{ "metadata" : [ { "playerId" : "1234", "sources" : [ { "matchId": 2 } ] }, { "playerId": "1248", "sources": [ { "score": 12.2 , "matchId": 1 } ] } ] }
{ "metadata" : [ { "playerId" : "1234", "sources" : [ { "matchId": 3 } ] }, { "playerId": "1248", "sources": [ { "matchId": 3 } ] } ] }
目标是找到playerId是否为1234且matchId是否为1,然后将isPlayed返回为true。源的结构不固定。可能有matchId以外的字段。
我写了一个udf,考虑元数据为WrappedArray [String]类型,并且能够读取playerId列
def hasPlayer = udf((metadata: WrappedArray[String], playerId: String) => {
metadata.contains(playerId)
})
df.withColumn("hasPlayer", hasPlayer(col("metadata"), col("superPlayerId")))
但我无法弄清楚如何查询给定playerId的matchId字段。我尝试将字段作为WrappedArray [WrappedArray [Long]]读取,但它在metadata.sources.matchId列的withColumn中给出了类型转换异常。
我对Spark相对较新。任何帮助都将深表感谢。
干杯!
答案 0 :(得分:2)
当您处理JSON时,请了解内置函数explode
,它将包含WrappedArray
的单个单元格转换为表示内部结构的多行。我认为这有帮助(两次):
df.select(explode($"metadata").as("metadata"))
.select($"metadata.playerId", explode($"metadata.sources.matchId").as("matchId"))
.filter($"matchId".equalTo(1))
.select($"matchId", lit(true).as("isPlayed"))
基本上我使用explode
创建多行(并重命名为方便的东西),将对象树导航到我想要的JSON字段,重复explode
/重命名进程{{1} },并过滤掉所有不是matchId
的内容。这样我最终可以使用1
函数对lit
的值进行“硬编码”,以获得名为true
的全新列因为所有不是isPlayed
的东西都消失了。
如果这不是您正在寻找的,希望它能为您提供一些指导。当您了解Spark时,1
library对您非常有帮助。