【问题标题】:Efficient reading nested parquet column in Spark高效读取 Spark 中的嵌套拼花列
【发布时间】:2019-12-11 08:22:24
【问题描述】:

我有以下(简化的)架构:

root
 |-- event: struct (nullable = true)
 |    |-- spent: struct (nullable = true)
 |    |    |-- amount: decimal(34,3) (nullable = true)
 |    |    |-- currency: string (nullable = true)
 |    |
 |    | ... ~ 20 other struct fields on "event" level

我正在尝试对嵌套字段求和

spark.sql("select sum(event.spent.amount) from event")

根据 spark 指标,我正在从磁盘读取 18 GB,这需要 2.5 分钟。

但是当我选择顶级字段时:

 spark.sql("select sum(amount) from event")

我在 4 秒内只读取了 2GB。

从物理计划中我可以看到,在嵌套结构的情况下,具有 所有字段整个事件 结构都是从镶木地板中读取的,这是一种浪费。

Parquet 格式应该能够从嵌套结构中提供所需的列,而无需全部读取(这是列式存储的重点)。有什么方法可以在 Spark 中有效地做到这一点?

【问题讨论】:

  • 你用什么版本的 spark?
  • 我用的是 Spark 2.4.2

标签: apache-spark parquet


【解决方案1】:

解决方案:

spark.sql("set spark.sql.optimizer.nestedSchemaPruning.enabled=true")
spark.sql("select sum(amount) from (select event.spent.amount as amount from event_archive)")

查询必须以子选择方式编写。您不能将所选列包装在聚合函数中。以下查询将破坏模式修剪:

select sum(event.spent.amount) as amount from event

SPARK-4502 涵盖了整个模式修剪工作

肮脏的解决方法也可以在加载时指定“投影模式”:

val DecimalType = DataTypes.createDecimalType(18, 4)
val schema = StructType(StructField("event", StructType(
      StructField("spent", StructType(
          StructField("amount", DecimalType, true) :: Nil
      ), true) :: Nil
    ), true) :: Nil
  )
 val df = spark.read.format("parquet").schema(schema).load(<path>)

【讨论】:

  • 是否应该将select sum(amount) from (select event.spent.amount as amount from event_archive) 包裹到 spark.sql() 中?
  • 是的,它应该在 spark.sql(...) 中,我已经更正了答案
猜你喜欢
  • 2021-07-23
  • 2017-04-29
  • 2021-04-10
  • 2018-06-19
  • 2023-03-18
  • 2020-10-26
  • 2019-10-26
  • 1970-01-01
  • 2015-07-12
相关资源
最近更新 更多