Pyspark展平RDD错误::太多值无法解包

时间:2019-09-25 05:50:53

标签: python apache-spark pyspark rdd

我正在尝试将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'}]) ]

我想整理数据,使其以以下格式显示

enter image description here

我将如何在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太大,因此无法转换为熊猫

1 个答案:

答案 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