具有混合值类型的MapType的PySpark UDF
我有一个类似这样的JSON输入 { "1": { "id": 1, "value": 5 }, "2": { "id": 2, "list": { "10": { "id": 10 }, "11": { "id": 11 }, "20": { "id": 20 } } }, "3": { "id": 3, "key": "a" } } 我需要合并3列并提取每列所需的值,这是我需要的输出: { "out": { "1": 5, "2": [10, 11, 20], "3": "a" } } 我试图创建一个UDF来将这3列转换为1,但我不知道如何使用混合值类型定义MapType—IntegerType、ArrayTypeIntegerType和StringType具有混合值类型的MapType的PySpark UDF,pyspark,pyspark-sql,Pyspark,Pyspark Sql,我有一个类似这样的JSON输入 { "1": { "id": 1, "value": 5 }, "2": { "id": 2, "list": { "10": { "id": 10 }, "11": { "id": 11 }, "20": {
提前谢谢 您需要使用StructType而不是MapType来定义UDF的结果类型,如下所示:
from pyspark.sql.types import *
udf_result = StructType([
StructField('1', IntegerType()),
StructField('2', ArrayType(StringType())),
StructField('3', StringType())
])
您需要使用StructType而不是MapType定义UDF的结果类型,如下所示:
from pyspark.sql.types import *
udf_result = StructType([
StructField('1', IntegerType()),
StructField('2', ArrayType(StringType())),
StructField('3', StringType())
])
MapType用于键、值对定义,不用于嵌套数据帧。你要找的是StructType
您可以使用createDataFrame直接加载它,但必须传递一个架构,因此这种方式更容易:
导入json
数据_json={
1: {
id:1,
价值:5
},
2: {
id:2,
名单:{
10: {
身份证号码:10
},
11: {
身份证号码:11
},
20: {
身份证号码:20
}
}
},
3: {
id:3,
关键字:a
}
}
a=[json.dumpsdata_json]
jsonRDD=sc.parallelizea
df=spark.read.jsonrdd
打印模式
根
|-1:struct nullable=true
||-id:long nullable=true
||-value:long nullable=true
|-2:struct nullable=true
||-id:long nullable=true
||-list:struct nullable=true
|| |-10:struct nullable=true
|| | |-id:long nullable=true
|| |-11:struct nullable=true
|| | |-id:long nullable=true
|| |-20:struct nullable=true
|| | |-id:long nullable=true
|-3:struct nullable=true
||-id:long nullable=true
||-key:string nullable=true
现在访问嵌套的数据帧。请注意,第2列比其他列嵌套得多:
嵌套的_cols=[2]
cols=[1,3]
将pyspark.sql.functions作为psf导入
df=df.select
cols+[psf.arraypsf.colc+.list.*.aliasc表示嵌套的_cols中的c]
df=df.select
[df[c].id.aliasc代表df.columns中的c]
根
|-1:long nullable=true
|-3:long nullable=true
|-2:array nullable=false
||-元素:long containsnall=true
它不完全是您的最终输出,因为您希望它嵌套在out列中:
将pyspark.sql.functions作为psf导入
df.selectpsf.struct*.aliasout.printSchema
根
|-out:struct nullable=false
||-1:long nullable=true
||-3:long nullable=true
||-2:array nullable=false
|| |-元素:long containsnall=true
最后回到JSON:
df.toJSON.first
'{1:1,3:3,2:[10,11,20]}'
MapType用于键、值对定义,不用于嵌套数据帧。你要找的是StructType
您可以使用createDataFrame直接加载它,但必须传递一个架构,因此这种方式更容易:
导入json
数据_json={
1: {
id:1,
价值:5
},
2: {
id:2,
名单:{
10: {
身份证号码:10
},
11: {
身份证号码:11
},
20: {
身份证号码:20
}
}
},
3: {
id:3,
关键字:a
}
}
a=[json.dumpsdata_json]
jsonRDD=sc.parallelizea
df=spark.read.jsonrdd
打印模式
根
|-1:struct nullable=true
||-id:long nullable=true
||-value:long nullable=true
|-2:struct nullable=true
||-id:long nullable=true
||-list:struct nullable=true
|| |-10:struct nullable=true
|| | |-id:long nullable=true
|| |-11:struct nullable=true
|| | |-id:long nullable=true
|| |-20:struct nullable=true
|| | |-id:long nullable=true
|-3:struct nullable=true
||-id:long nullable=true
||-key:string nullable=true
现在访问嵌套的数据帧。请注意,第2列比其他列嵌套得多:
嵌套的_cols=[2]
cols=[1,3]
将pyspark.sql.functions作为psf导入
df=df.select
cols+[psf.arraypsf.colc+.list.*.aliasc表示嵌套的_cols中的c]
df=df.select
[df[c].id.aliasc代表df.columns中的c]
根
|-1:long nullable=true
|-3:long nullable=true
|-2:array nullable=false
||-元素:long containsnall=true
它不完全是您的最终输出,因为您希望它嵌套在out列中:
将pyspark.sql.functions作为psf导入
df.selectpsf.struct*.aliasout.printSchema
根
|-out:struct nullable=false
||-1:long nullable=true
||-3:long nullable=true
||-2:array nullable=false
|| |-元素:long containsnall=true
最后回到JSON:
df.toJSON.first
'{1:1,3
:3,2:[10,11,20]}'
很抱歉,我没有提到这一点,但是结构2可能有可为空的项,例如一些记录可能只有10个。如果可能的话,有没有办法使Structure2的扁平化成为动态的,而不管嵌套的元素是什么?2:{id:2,列表:{10:{id:10}}}谢谢!我尝试了col2.list.*.getFieldid,但我猜getField不能与*一起使用,因为错误是表达式“unsolvedExtractValue”中“*”的有效用法;我已经更新了我的答案,所以它是动态的。2有可为空的项这一事实不会改变任何东西。当你使用*时,它会使结构变得平坦,从而创建多个列,因此当你尝试访问id时,实际上是在告诉它一次访问多个列的子列,这是不可能的。希望这有帮助,别忘了将问题标记为solvedSorry我没有提到这一点,但是结构2可以有可为空的项,例如一些记录可能只有10个。如果可能的话,有没有办法使Structure2的扁平化成为动态的,而不管嵌套的元素是什么?2:{id:2,列表:{10:{id:10}}}谢谢!我尝试了col2.list.*.getFieldid,但我猜getField不能与*一起使用,因为错误是表达式“unsolvedExtractValue”中“*”的有效用法;我已经更新了我的答案,所以它是动态的。2具有可为空的项这一事实不会改变任何东西。当您使用*时,它会使结构变得平坦,从而创建多个列,因此当您尝试访问id时,实际上是在告诉它一次访问多个列的子列,这是不可能的。希望这有所帮助,不要忘记将问题标记为solvedGotcha,这是可行的。只是想知道,如果没有UDF,是否有任何方法可以实现这一点?明白了,这是有效的。只是想知道,如果没有UDF,是否还有实现这一目标的方法?