提问者:小点点

在Spark中高效读取嵌套镶木地板列


我有以下(简化的)模式:

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")

根据火花指标,我从磁盘读取18 GB,需要2.5分钟。

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

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

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

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

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


共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>)