【问题标题】:How to have different schemas within parquet partitions如何在镶木地板分区中有不同的模式
【发布时间】:2020-09-06 08:58:48
【问题描述】:

我已将 json 文件读入数据框。 json 可以有一个特定于名称的结构字段消息,如下所示。

Json1
{
   "ts":"2020-05-17T00:00:03Z",
   "name":"foo",
   "messages":[
      {
         "a":1810,
         "b":"hello",
         "c":390
      }
   ]
}

Json2
{
   "ts":"2020-05-17T00:00:03Z",
   "name":"bar",
   "messages":[
      {
         "b":"my",
         "d":"world"
      }
   ]
}

当我将 jsons 中的数据读取到 Dataframe 中时,我得到如下架构。

root
 |-- ts: string (nullable = true)
 |-- name: string (nullable = true)
 |-- messages: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- a: long (nullable = true)
 |    |    |-- b: string (nullable = true)
 |    |    |-- c: long (nullable = true)
 |    |    |-- d: string (nullable = true)

这很好。现在,当我保存到按名称分区的 parquet 文件时,如何在 foo 和 bar 分区中有不同的模式?

path/name=foo
root
 |-- ts: string (nullable = true)
 |-- name: string (nullable = true)
 |-- messages: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- a: long (nullable = true)
 |    |    |-- b: string (nullable = true)
 |    |    |-- c: long (nullable = true)

path/name=bar
root
 |-- ts: string (nullable = true)
 |-- name: string (nullable = true)
 |-- messages: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- b: string (nullable = true)
 |    |    |-- d: string (nullable = true)

当我从根路径读取数据时,如果我得到包含 foo 和 bar 的所有字段的架构,我很好。但是当我从 path/name=foo 读取数据时,我只期望 foo 模式。

【问题讨论】:

    标签: apache-spark apache-spark-sql parquet


    【解决方案1】:

    1. Partitioning & Storing as Parquet file:

    如果您保存为 parquet 格式,则在阅读 path/name=foo specify the schema 时,包括所有 必填字段(a、b、c ), 然后 spark 只加载那些字段。

    • 如果我们won't指定架构,那么所有字段(a、b、c、d)都将包含在数据框中

    EX:

    schema=define structtype...schema
    spark.read.schema(schema).parquet(path/name=foo).printSchema()
    

    2.Partitioning & Storing as JSON/CSV file:

    那么 Spark 不会将 b,d 列添加到 path/name=foo 文件中,所以当我们只读取 name=foo 目录时,我们不会得到 @987654330 @ 数据中包含的列。

    EX:

    spark.read.json(path/name=foo).printSchema()
    spark.read.csv(path/name=foo).printSchema()
    

    【讨论】:

    • 但是如果数据是用 partitionBy 子句保存的,我认为分区仍然会包含不需要的列,但都是空值。
    • @ShubhamJain,这仅适用于列格式,但如果我们存储 json,那么 null 将不会被存储..!
    • 动态构建一个数据框/数据集到每个名称分区然后将它们保存到路径/名称=的最佳方法是什么?在上面的示例中,我只有 2 个名字,但在我的输入中,我可以有 100 个名字。
    【解决方案2】:

    您可以在将数据框保存在分区中之前更改架构,为此您必须过滤分区记录,然后将它们保存在相应的文件夹中

    #this will select only not null columns which will drop col d from foo and a,c from bar
    df = df.filter(f.col('name')='foo').select(*[c for c in df.columns if df.filter(f.col(c).isNotNull()).count() > 0])
    
    #then save the df
    df.write.json('path/name=foo')
    

    现在每个分区都有不同的架构。

    【讨论】:

      猜你喜欢
      • 2016-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-13
      • 2018-06-28
      • 2016-10-05
      • 1970-01-01
      相关资源
      最近更新 更多