GH-48561: [C++][Parquet] Optimize column reader by fusing definition level decoding with counting - #51109
GH-48561: [C++][Parquet] Optimize column reader by fusing definition level decoding with counting#51109Shockp wants to merge 3 commits into
Conversation
Add GetBatchAndCount support to RleRunDecoder, BitPackedRunDecoder, RleBitPackedDecoder, and BitPackedDecoder. The new operation decodes values while also counting occurrences of a target value. RLE runs compute the count directly from the run value and length, avoiding an additional scan of the decoded output. Bit-packed runs count the values after unpacking them into the output buffer. Add tests covering decoded output, matching counts, partial batches, and mixed RLE/bit-packed runs.
…nting Use the new decode-and-count operation when reading definition levels. Add LevelDecoder::DecodeAndCount to decode levels while counting occurrences of the maximum definition level, preserving the existing level validation. Update the column reader to use the matching count directly when determining the number of physical values to decode, removing the separate std::count pass over the definition level buffer.
Add benchmarks comparing separate definition level decoding and counting with the fused DecodeAndCount path. Cover RLE and bit-packed encodings across different maximum levels, batch sizes, and level repeat counts.
|
|
|
@AntoinePrv Could you help review this please? |
|
Something like this was already attempted in #50682, how is this one different? |
|
@ursabot please benchmark lang=C++ |
|
Benchmark runs are scheduled for commit 9e4a871. Watch https://buildkite.com/apache-arrow and https://conbench.arrow-dev.org for updates. A comment will be posted here when the runs are complete. |
I am on holidays till Sunday. I will read that PR deeper. But it seems he tried a different approach. I will wait for the benchmark results as well. |
|
@wgtmac is it bugged the benchmark? It was started 4 days ago. |
|
@Shockp The results weren't posted here apparently but you can find them there: |
Which were your conclusion about the results? I think there are some good improvements and not many regressions. |
|
@Shockp Agreed. It also seems that only the |
|
This may also conflict heavily with the optimizations @AntoinePrv is working on in #50629. Can both of you discuss how to reconcile these? |
|
This seems to only add a new method so I think it is going to be easier for me to rebase on this in GH-50629 than the other way around. It seems to me that the new method is not used anywhere here, so I am curious on the use case. |
Yes, that matches my understanding. This PR currently optimizes the TypedColumnReader::ReadBatch path. The Arrow-array / RecordReader path is not the main target of this change, and #50629 appears to be addressing that path more directly. |
I think there may be a small misunderstanding regarding the use of the new method. DecodeAndCount() is used in this PR by the TypedColumnReader::ReadBatch path: TypedColumnReaderImpl::ReadLevels() It replaces the previous definition-level decode followed by a separate std::count() pass. From what I understand, #50629 mainly reworks the RecordReader / Arrow-array path and introduces the bitmap-based optional-field optimization, so the two PRs seem complementary even though they touch some of the same decoder code. I agree that rebasing #50629 on top of this PR sounds easier than the other way around. If there is anything in this API that would make that rebase harder, I'm happy to adjust it. |
Ha yes sorry, I missed that part. I was focused on the validation check. |
|
@pitrou The other developer will rebase his work on top of this. Is this PR ready to be merged, or do we need to wait? |
Rationale for this change
Definition levels in the Parquet column reader are currently decoded into
a buffer and then scanned separately with
std::countto determine howmany physical values need to be decoded.
This adds an extra pass over the decoded definition levels.
For RLE-encoded levels, the number of matching values can often be
determined directly from the run value and run length while the output is
being materialized.
What changes are included
GetBatchAndCountsupport to the RLE and bit-packed decoders.metadata without scanning the decoded output.
LevelDecoder::DecodeAndCount, preserving the existing levelvalidation.
levels.
std::countpass from the column reader.Benchmarks
parquet-column-reader-benchmark, pinned to one CPU, 20 repetitions.The improvement increases with RLE run length because matching values can
be counted from run metadata instead of rescanning the materialized output.
The bit-packed path remains approximately neutral.
Closes #48561.