Parquetファイルには、ブロックごとの行数フィールドが含まれています。 Sparkはある時点でそれを読んでいるようです( SpecificParquetRecordReaderBase.Java#L151
)。
私はこれをspark-Shell
で試しました:
sqlContext.read.load("x.parquet").count
そして、Sparkは2つのステージを実行し、DAGでのさまざまな集約ステップを示しました。これは、行数を使用する代わりに、通常どおりファイルを読み取ることを意味すると思います。 (私は間違っている可能性があります。)
質問は次のとおりです。count
を実行すると、Sparkはすでに行数フィールドを使用していますか?それらのフィールドを使用する別のAPIはありますか?これらのフィールドに依存することは、何らかの理由で悪い考えですか?
正解です。count
を実行しているとき、Sparkはすでにrowcountsフィールドを使用しています。
詳細を少し掘り下げて、 SpecificParquetRecordReaderBase.Java は フラットスキーマコミットを使用する場合のParquetスキャンパフォーマンスの向上 の一部として [SPARK-11787]スピードアップフラットスキーマ用の寄木細工のリーダー 。このコミットはSpark 1.6ブランチの一部として含まれていることに注意してください。
クエリが行数の場合、説明したとおりに機能します(つまり、メタデータを読み取ります)。述語が最小/最大値によって完全に満たされている場合、そのはも機能するはずですが、完全には検証されていません。これらのParquetフィールドを使用することは悪い考えではありませんが、前のステートメントで暗示されているように、重要な問題は、述語フィルタリングがメタデータと一致することを確認して、正確なカウントを行うことです。
2つの段階がある理由を理解しやすくするために、count()ステートメントの実行時に作成されるDAGを次に示します。
2つのステージを掘り下げるときは、最初のステージ(ステージ25)がファイルスキャンを実行し、2番目のステージ(ステージ26)がカウントのシャッフルを実行していることに注意してください。
検証してくれたNongLi( SpecificParquetRecordReaderBase.Java commitの作成者)に感謝します!
_Dataset.count
_とParquetの間のブリッジに追加のコンテキストを提供するために、これを取り巻く内部ロジックのフローは次のとおりです。
VectorizedParquetRecordReader
に渡すことは、実際には空のParquetメッセージです。InternalRow
を返すイテレータ内で上記をラップする必要があります。寄木細工のファイル形式を内部的に操作するために、Apache Sparkは、InternalRow
を返すイテレーターでロジックをラップします。詳細については、 InternalRow.scala)を参照してください。 。最終的に、count()
集計関数は、このイテレーターを使用して、基になるParquetデータソースと対話します。ところで、これは、ベクトル化されたParquetリーダーとベクトル化されていないParquetリーダーの両方に当てはまります。
したがって、Dataset.count()
をParquetリーダーとブリッジするためのパスは次のとおりです。
Dataset.count()
呼び出しは、単一のcount()集計関数を持つ集計演算子に計画されています。詳細については、 寄木細工の数のメタデータの説明 を参照してください。