PySpark:使用具有1000个字段但行数可变的行的架构创建RDD-> DF-> Parquet

时间:2019-03-11 22:31:25

标签: apache-spark hadoop elasticsearch pyspark parquet

我正在尝试读取一个 ElasticSearch 索引,该索引包含数百万个文档,每个文档具有可变数量的字段。我有一个架构,其中有1000个字段,每个字段都有自己的名称和类型。

现在,当我创建 RDD ES-Hadoop 连接器,然后通过指定架构将其转换为 DataFrame 时,它无法显示-

  

输入行没有预期的数量的值   模式

我有几个问题。 1.是否可能有一个 RDD / DF ,其中行包含可变数量的字段?如果不是,除了为每列中的缺失字段添加空值之外,还有什么选择?

  1. 我看到默认情况下,当我使用StringType调用时, Spark 会将所有内容转换为sc.newAPIHadoopRDD()。如何根据架构中的字段名称对它们进行类型转换以更正类型?某种映射?

  2. 我想以 Parquet 格式编写此文件,并将模式添加到文件中。与具有1000个字段的架构相比,那些缺少的字段会发生什么情况。

1 个答案:

答案 0 :(得分:1)

  1. 您不能具有可变的列数,但是可以使用集合类型的一列,例如Array或Map,在python中对应于字典。这使您可以在列中存储长度可变的数据。否则,您需要为架构中的每个列都有一个值。通常,您会用空值填充缺失值。

  2. 如果您已经有一个数据框,并且您有一个函数get_column_type从列名中获取类型名称,则可以像这样重铸整个数据框:

    import pyspark.sql.functions as F
    select_expressions = [ F.col(column_name).cast(get_column_type(column_name)) for column_name in column_list]
    recasted_df = df.select(*select_expressions)
    
  3. 镶木地板文件将具有数据框中具有的任何列。如果要在文件中包含1000个字段,则它们必须在数据框中,因此您必须用空值或其他某个值来填充缺失的值。

现在,如果将所有这些点放在一起,则可能需要执行以下操作:

  • 将每个弹性文档读入具有id字段和MapType类型的doc字段的行中。
  • explode doc字段,因此您现在有3列:idkeyvalue,其中的每个键为一行每个文档。此时,您可以写入镶木地板文件并完成该过程。

如果您想要具有完整架构的数据框,则必须执行以下额外步骤:

  • 将结果枢纽为每个ID 仅生成一行,并为文档中的每个键生成一列,并带有其相应的值:pivoted_df = df.groupBy('id').pivot('key').agg(F.first('value')
  • 此数据框具有数据中存在的所有字段。如果您知道完整的架构,则可以为缺少的列添加伪列:df = df.withColumn('new_column', lit(None).cast(StringType())
  • 最后,使用点2的代码重铸各列,并删除列id。您可以将其写入镶木地板,它将在您的大架构中包含所有列。