我正在尝试将RDD中的数据扁平化。 RDD被构造为一个由4个元组组成的列表,其中第一个元素为primary_id,第二个元素为字典列表,第三个和第四个元素每个都包含一个包含字典的列表。
rdd= [('xxxxx99', [{'cov_id':'Q', 'cov_cd':'100','cov_amt':'100', 'cov_state':'AZ'},
{'cov_id':'Q', 'cov_cd':'33','cov_amt':'200', 'cov_state':'AZ'},
{'cov_id':'Q', 'cov_cd':'64','cov_amt':'10', 'cov_state':'AZ'}],
[{'pol_cat_id':'234','pol_dt':'20100220'}],
[{'qor_pol_id':'23492','qor_cd':'30'}]),
('xxxxx86', [{'cov_id':'R', 'cov_cd':'20','cov_amt':'100', 'cov_state':'TX'},
{'cov_id':'R', 'cov_cd':'44','cov_amt':'500', 'cov_state':'TX'},
{'cov_id':'R', 'cov_cd':'66','cov_amt':'50', 'cov_state':'TX'}],
[{'pol_cat_id':'532','pol_dt':'20091020'}],
[{'qor_pol_id':'49320','qor_cd':'21'}]) ]
我想整理数据,使其以以下格式显示
我将如何在Pyspark中做到这一点?
这是我尝试过的操作,但这给我一个错误:要打开的元组太多
def flatten_map(record):
try:
yield(record)
# Unpack items
id, items, line, pls = record
pol_id = pls["pol_cat_id"]
pol_dt = pls["pol_dt"]
qor_id = pls["qor_pol_id"]
for item in items:
yield (id,item["cov_id"],item["cov_cd"], item["cov_amt"], item["cov_state"], pol_id, pol_dt, qor_id), 1
except Exception as e:
pass
result = (rdd
# Expand data
.flatMap(flatten_map)
# Flatten tuples
.map(lambda x: x[0], ))
如果需要,我可以发布完整错误,但为了简洁起见,
ValueError: too many values to unpack (expected 2)
注意:由于RDD太大,因此无法转换为熊猫
答案 0 :(得分:1)
IIUC,您可以使用列表推导来遍历4项元组(1个字符串+ 3个列表)的第二项,从而运行flatMap(),例如:
from pyspark.sql import Row
myrdd = sc.parallelize(rdd)
myrdd.flatMap(lambda x: [ ({'primary_id':x[0]}, z, x[2][0], x[3][0]) for z in x[1] ] ).collect()
#[({'primary_id': 'xxxxx99'},
# {'cov_id': 'Q', 'cov_cd': '100', 'cov_amt': '100', 'cov_state': 'AZ'},
# {'pol_cat_id': '234', 'pol_dt': '20100220'},
# {'qor_pol_id': '23492', 'qor_cd': '30'}),
# ......
简短说明:在flatMap函数的列表理解中,除了迭代第二项x[1]
(作为z
这是一个字典)之外,我还转换了第一个String将项目 x [0] 放入一个只有一个条目的字典:{"primary_id":x[0]}
并取出 x [2] 和 x [3] <的第一项/ em>,它们都是字典。
因此,在运行上述flatMap函数之后,RDD元素变为包含4个字典的元组,接下来需要做的就是将它们合并。以下是我的示例代码,用于将4字典的元组映射到Row对象,您可能必须更改逻辑以处理异常和遗漏字段以适应自己的要求。
cols = ['primary_id', 'cov_id', 'cov_cd', 'cov_amt', 'cov_state', 'pol_cat_id', 'pol_dt', 'qor_pol_id', 'qor_cd']
def merge_dict(arr, cols):
row = {}
try:
for e in arr:
if type(e) is dict: row.update(e)
except:
pass
finally:
return Row(**dict({ c:row.get(c, None) for c in cols })) if row else None
myrdd.flatMap(lambda x: [ ({'primary_id':x[0]}, z, x[2][0], x[3][0]) for z in x[1] ] ) \
.map(lambda x: merge_dict(x, cols)) \
.filter(bool) \
.toDF() \
.show()
+-------+------+------+---------+----------+--------+----------+------+----------+
|cov_amt|cov_cd|cov_id|cov_state|pol_cat_id| pol_dt|primary_id|qor_cd|qor_pol_id|
+-------+------+------+---------+----------+--------+----------+------+----------+
| 100| 100| Q| AZ| 234|20100220| xxxxx99| 30| 23492|
| 200| 33| Q| AZ| 234|20100220| xxxxx99| 30| 23492|
| 10| 64| Q| AZ| 234|20100220| xxxxx99| 30| 23492|
| 100| 20| R| TX| 532|20091020| xxxxx86| 21| 49320|
| 500| 44| R| TX| 532|20091020| xxxxx86| 21| 49320|
| 50| 66| R| TX| 532|20091020| xxxxx86| 21| 49320|
+-------+------+------+---------+----------+--------+----------+------+----------+
顺便说一句。。如果要使原始功能正常工作,请检查以下5行,其中包含 #<--
:
def flatten_map(record):
try:
#yield(record) #<-- comment this out, no need unprocessed data in output
# Unpack items
id, items, line, pls = record
pol_id = line[0]["pol_cat_id"] #<-- from line[0] not pls
pol_dt = line[0]["pol_dt"] #<-- from line[0] not pls
qor_id = pls[0]["qor_pol_id"] #<-- from pls[0] not pls
for item in items:
#<-- below line removed the ending ", 1", thus no need the last map() function to flatten tuples
yield (id,item["cov_id"],item["cov_cd"], item["cov_amt"], item["cov_state"], pol_id, pol_dt, qor_id)
except Exception as e:
pass