Parquet文件包含每个块的行计数字段。 Spark似乎在某个时刻(SpecificParquetRecordReaderBase.java#L151
)读取它。
我在spark-shell
尝试了这个:
sqlContext.read.load("x.parquet").count
Spark分两个阶段,显示了DAG中的各种聚合步骤。我认为这意味着它正常读取文件而不是使用行计数。 (我可能错了。)
问题是:当我运行count
时,Spark是否已使用行计数字段?是否有其他API可以使用这些字段?出于某种原因依赖这些领域是个坏主意吗?
答案 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。
当进入这两个阶段时,请注意第一个阶段(阶段25)正在运行文件扫描,而第二阶段(阶段26)运行洗牌以进行计数。
感谢Nong Li(SpecificParquetRecordReaderBase.java提交的作者)进行验证!
为了在Dataset.count
和Parquet之间的桥梁上提供额外的上下文,围绕此内部逻辑的流程是:
VectorizedParquetRecordReader
实际上是一个空的Parquet消息InternalRow
。要在内部使用Parquet文件格式,Apache Spark会使用返回InternalRow
的迭代器来包装逻辑;更多信息可以在InternalRow.scala中找到。最终,count()
聚合函数使用此迭代器与底层的Parquet数据源交互。顺便说一句,对于矢量化和非矢量化的Parquet读取器都是如此。
因此,要将Dataset.count()
与Parquet阅读器联系起来,路径为:
Dataset.count()
调用计划在具有单个count()聚合函数的聚合运算符中。有关详细信息,请参阅Parquet Count Metadata Explanation。
答案 1 :(得分:0)
我们也可以使用
java.text.NumberFormat.getIntegerInstance.format(sparkdf.count)