zipWithIndex之后将RDD转换为DF后出现pyspark DF.show()错误

时间:2019-08-12 19:12:25

标签: apache-spark pyspark apache-spark-sql

我似乎正在遵循记录的方法来显示从具有模式的RDD转换的DF。但是很明显,我缺少一些重要的要点。然后如下:

# Original schema + Index for zipWithIndex with variations on this
schema = StructType(result_df.schema.fields[:] + [StructField("index", LongType(), True)])
rdd = result_df.rdd.zipWithIndex()
df = spark.createDataFrame(rdd, schema)
#df.select("*").show()
print(schema)

执行操作之前,该架构如下所示:

df:pyspark.sql.dataframe.DataFrame
  ARRAY_COLS:array
     element:string
  index:long

模式:

StructType
 (List(StructField
 (ARRAY_COLS,ArrayType(StringType,true),false),
  StructField(index,LongType,true)))

使用.show执行动作后,它立即爆炸。在这种情况下,我的工作是动态的,但并不是必须的。

完整列表

from functools import reduce
from pyspark.sql.functions import lower, col, lit, concat, split
from pyspark.sql.types import * 
from pyspark.sql import Row
from pyspark.sql import functions as f

source_df = spark.createDataFrame(
   [
      (1, 11, 111),
      (2, 22, 222)
   ],
   ["colA", "colB", "colC"]
                             )

intermediate_df = (reduce(
                lambda df, col_name: df.withColumn(col_name, concat(lit(col_name), lit("_"), col(col_name))),
                source_df.columns,
                source_df
         )     )
intermediate_df.show(truncate=False)

allCols = [x for x in intermediate_df.columns]
result_df = intermediate_df.select(f.concat_ws(',', *allCols).alias('CONCAT_COLS'))
result_df.show(truncate=False) 

result_df = result_df.select(split(col("CONCAT_COLS"), ",\s*").alias("ARRAY_COLS"))
result_df.show(truncate=False) 

#######

schema = StructType(result_df.schema.fields[:] + [StructField("index", LongType(), True)])

rdd = result_df.rdd.zipWithIndex()
df = spark.createDataFrame(rdd, schema)
df.select("*").show() 
print(schema)

1 个答案:

答案 0 :(得分:1)

如果您查看rdd,问题将更加清楚:

print(rdd.collect())
#[(Row(ARRAY_COLS=[u'colA_1', u'colB_11', u'colC_111']), 0),
# (Row(ARRAY_COLS=[u'colA_2', u'colB_22', u'colC_222']), 1)]

请注意,它是一个包含Row对象和索引的元组。

我看到了两种选择:

1)使用元组理解将值从Rowmap的{​​{1}}提取到与rdd匹配的元组:

schema

这将使用每个记录的内容创建一个新的rdd1 = rdd.map( lambda row: tuple(row[0].asDict()[c] for c in schema.fieldNames()[:-1]) + (row[1],) ) df1 = spark.createDataFrame(rdd1, schema) df1.show(truncate=False) #+---------------------------+-----+ #|ARRAY_COLS |index| #+---------------------------+-----+ #|[colA_1, colB_11, colC_111]|0 | #|[colA_2, colB_22, colC_222]|1 | #+---------------------------+-----+

tuple

2)通过添加print(rdd1.collect()) #[([u'colA_1', u'colB_11', u'colC_111'], 0), # ([u'colA_2', u'colB_22', u'colC_222'], 1)] 并解压缩现有Row来构建新的index

Row

现在每个记录都是一个rdd2 = rdd.map(lambda row: Row(index=0, **row[0].asDict())) df2 = spark.createDataFrame(rdd2, schema) df2.show(truncate=False) #+---------------------------+-----+ #|ARRAY_COLS |index| #+---------------------------+-----+ #|[colA_1, colB_11, colC_111]|0 | #|[colA_2, colB_22, colC_222]|1 | #+---------------------------+-----+ ,其中添加了Row

index

但是,因此,您无需在对print(rdd2.collect()) #[Row(ARRAY_COLS=[u'colA_1', u'colB_11', u'colC_111'], index=0), # Row(ARRAY_COLS=[u'colA_2', u'colB_22', u'colC_222'], index=0)] 的调用中使用schema

createDataFrame

方法1使用您已经定义的现有spark.createDataFrame(rdd2).show() #+---------------------------+-----+ #|ARRAY_COLS |index| #+---------------------------+-----+ #|[colA_1, colB_11, colC_111]|0 | #|[colA_2, colB_22, colC_222]|1 | #+---------------------------+-----+ ,而方法2可能在代码方面更紧凑(但需要硬编码的schema)。