GH-3596: Add RowRanges.Builder for incremental construction from selected row indices#3597
Conversation
…m selected row indices ### Rationale for this change Opening up APIs needed by a later materialization feature in Spark. External readers need to assemble a RowRanges incrementally from a stream of selected row indices (e.g. produced by a downstream filter or join) without having to know page boundaries ahead of time. ### What changes are included in this PR? Adds a Builder to RowRanges that takes a strictly-increasing sequence of selected row indices via addSelected(long) and coalesces consecutive indices into Range entries. Out-of-order or duplicate calls throw IllegalArgumentException. ### Are these changes tested? Yes. TestRowRanges covers single/multiple/coalesced ranges, the empty builder case, and the out-of-order/duplicate rejection paths. ### Are there any user-facing changes? No. Closes apache#3596 Co-authored-by: Matt Butrovich <mbutrovich@gmail.com>
e11f3d9 to
58857df
Compare
|
@wgtmac, could you please take a look at this PR? |
|
Do you have any advice on this new API? @gszadovszky |
…dRowGroup compatibility Recreate org.apache.parquet.internal.filter2.columnindex.RowRanges as a deprecated subclass of the relocated org.apache.parquet.filter2.columnindex.RowRanges so the released ParquetFileReader#readFilteredRowGroup(int, RowRanges) signature keeps linking. Add a deprecated readFilteredRowGroup overload taking the old internal type that delegates to the new one, and drop the japicmp exclusions for that method now that it is compatible. Other internal-only surfaces (RowRanges statics, Range, ColumnIndexFilter return types) remain relocated without a bridge.
|
@wgtmac, @gszadovszky, please let me know how to proceed with this PR. |
|
Thanks @wgtmac. I'm a bit confused, so let me lay out how things stand now: How old and new relate. The real The method you commented on. That overload is the deprecated one — Why the excludes exist. They're not caused by On dropping the excludes. Reversing the inheritance ( The other option is to fully separate Do you have a concrete approach in mind? I'm happy to explore it. |
|
@wgtmac , any suggestion on the above? Do you think the current implementation is fine or shall try to fully separate old and new |
wgtmac
left a comment
There was a problem hiding this comment.
Sorry for the delay. Now it overall looks good. I just have two more comments. Let me know what you think. Thanks!
Check rowIndex <= runEnd before evaluating runEnd + 1, so the strictly-increasing guard keeps working when runEnd is Long.MAX_VALUE (runEnd + 1 would otherwise overflow to Long.MIN_VALUE and let a follow-up index start a bogus new run).
… move it to internal.RowRanges Adds a range-level Builder.addSelectedRange(from, to) (addSelectedRow now delegates to it), so RowRanges can be built from page ranges through the public API. create() is reimplemented on top of the builder and moved to the deprecated internal.RowRanges shim, where the released 1.17 internal.RowRanges.create(...) signature lived. The public RowRanges no longer references the internal OffsetIndex, and ColumnIndexFilter now builds via the public builder rather than a deprecated method. Behavior note: the builder rejects overlapping ranges instead of silently unioning them (as the old add() did). Offset-index pages never overlap, so the filter path is unaffected; TestRowRanges#testCreate is updated to feed realistic adjacent (non-overlapping) page ranges.
wgtmac
left a comment
There was a problem hiding this comment.
Thanks @peter-toth, now it looks good to me. It would be good to wait for @gszadovszky to take a look in case I missed anything.
gszadovszky
left a comment
There was a problem hiding this comment.
It looks good to me, too.
Thank you @peter-toth and @wgtmac!
|
Thank you @wgtmac and @gszadovszky for the review! |
Rationale for this change
This PR is based on @mbutrovich's previous work.
Opening up APIs needed by a later materialization feature in Spark. External readers need to assemble a
RowRangesincrementally from a stream of selected row indices (e.g. produced by a downstream filter or join) without having to know page boundaries ahead of time.Since
RowRangesis the type external readers must work with, this PR also promotes it out of theorg.apache.parquet.internal.*package into a supported location.What changes are included in this PR?
RowRanges.Builderfor incremental construction. It accepts a strictly-increasing sequence of selected rows viaaddSelectedRow(long rowIndex)— or ranges viaaddSelectedRange(long from, long to), withaddSelectedRowdelegating to it — and coalesces consecutive/adjacent entries intoRanges. Out-of-order, overlapping, duplicate, negative, orfrom > tocalls throwIllegalArgumentException.build()returns an independent snapshot, so the builder can be reused afterwards.Builderisfinalwith a private constructor.RowRanges(withRangeandBuilder) fromorg.apache.parquet.internal.filter2.columnindextoorg.apache.parquet.filter2.columnindex.org.apache.parquet.internal.filter2.columnindex.RowRangessubclass is kept, andParquetFileReader.readFilteredRowGroup(int, RowRanges)gains a deprecated overload (taking the old internal type) that delegates to the new one. Both are marked for removal in 2.0.RowRanges.create(...)on top of the newBuilderand keeps it on the deprecatedinternal.RowRanges(preserving the releasedinternal.RowRanges.create(...)signature), so the publicRowRangesno longer references the internalOffsetIndex;ColumnIndexFilternow builds via the public builder.internal-only surfaces (RowRangesstatics,Range,ColumnIndexFilterreturn types) are relocated without a bridge, as theinternalpackage carries no compatibility guarantee.Are these changes tested?
Yes.
TestRowRangescovers single/multiple/coalesced ranges, the empty builder case, the out-of-order/duplicate/negative rejection paths,addSelectedRangecoalescing and overlap/from > torejection, theLong.MAX_VALUEedge case, and thatbuild()returns a snapshot independent of the builder. ExistingTestColumnIndexFilterandTestParquetFileReaderRowRangescontinue to pass against the relocated type.Are there any user-facing changes?
Yes.
RowRanges(andRange/Builder) is now available at the supported packageorg.apache.parquet.filter2.columnindex. The oldorg.apache.parquet.internal.filter2.columnindex.RowRangesandParquetFileReader.readFilteredRowGroup(int, <internal> RowRanges)remain as deprecated shims and will be removed in 2.0.Closes #3596