Spark中的快速镶木地板行数

时间:2016-11-16 10:15:03

标签: apache-spark parquet

Parquet文件包含每个块的行计数字段。 Spark似乎在某个时刻(SpecificParquetRecordReaderBase.java#L151)读取它。

我在spark-shell尝试了这个:

sqlContext.read.load("x.parquet").count

Spark分两个阶段,显示了DAG中的各种聚合步骤。我认为这意味着它正常读取文件而不是使用行计数。 (我可能错了。)

问题是:当我运行count时,Spark是否已使用行计数字段?是否有其他API可以使用这些字段?出于某种原因依赖这些领域是个坏主意吗?

2 个答案:

答案 0 :(得分:11)

这是正确的,当您运行count时,Spark已经在使用rowcounts字段。

稍微深入了解详细信息,SpecificParquetRecordReaderBase.java引用Improve Parquet scan performance when using flat schemas commit作为[SPARK-11787] Speed up parquet reader for flat schemas的一部分。注意,此提交包含在Spark 1.6分支中。

如果查询是行计数,它几乎按照您描述的方式工作(即读取元数据)。如果最小/最大值完全满足谓词,那么应该也可以正常工作,尽管这不是完全验证的。使用这些Parquet字段并不是一个坏主意,但正如前面的声明所暗示的那样,关键问题是确保谓词过滤与元数据匹配,以便您进行准确的计数。

为了帮助理解为什么有两个阶段,这里是运行count()语句时创建的DAG。

enter image description here

当进入这两个阶段时,请注意第一个阶段(阶段25)正在运行文件扫描,而第二阶段(阶段26)运行洗牌以进行计数。

enter image description here enter image description here

感谢Nong Li(SpecificParquetRecordReaderBase.java提交的作者)进行验证!

更新

为了在Dataset.count和Parquet之间的桥梁上提供额外的上下文,围绕此内部逻辑的流程是:

  • Spark不读取任何Parquet列来计算计数
  • 将Parquet架构传递给VectorizedParquetRecordReader实际上是一个空的Parquet消息
  • 使用存储在Parquet文件页脚中的元数据计算计数。 涉及在迭代器中包含上述内容,该迭代器每InternalRow.scala返回InternalRow

要在内部使用Parquet文件格式,Apache Spark会使用返回InternalRow的迭代器来包装逻辑;更多信息可以在InternalRow.scala中找到。最终,count()聚合函数使用此迭代器与底层的Parquet数据源交互。顺便说一句,对于矢量化和非矢量化的Parquet读取器都是如此。

因此,要将Dataset.count()与Parquet阅读器联系起来,路径为:

  • Dataset.count()调用计划在具有单个count()聚合函数的聚合运算符中。
  • 在计划时为聚合运算符生成Java代码以及count()聚合函数。
  • 生成的Java代码与底层数据源ParquetFileFormat与RecordReaderIterator进行交互,RecordReaderIterator由Spark数据源API在内部使用。

有关详细信息,请参阅Parquet Count Metadata Explanation

答案 1 :(得分:0)

我们也可以使用

java.text.NumberFormat.getIntegerInstance.format(sparkdf.count)