Repository navigation
[Java] BigQueryIO: support integer-range partitioning in Write - #40790
mxtymoshyk wants to merge 2 commits into
Conversation
Add Write.withRangePartitioning(...) for single tables, and withRangePartitioning() for table functions and DynamicDestinations that set a RangePartitioning on each TableDestination. Range partitioning travels in a new TableDestinationCoderV4, used only when the option is set, so existing pipelines keep their coder. Turning it on requires draining and restarting a running pipeline. FILE_LOADS temp tables now copy the range partitioning of an existing destination table, so the copy jobs into it succeed. Fixes apache#27069
There was a problem hiding this comment.
📋 Review Summary
This PR adds support for BigQuery integer range partitioning (RangePartitioning) across BigQueryIO.Write, TableDestination, DynamicDestinations, and the underlying write transforms (Batch Loads, Streaming Inserts, and Storage Write API). It also introduces TableDestinationCoderV4 while carefully preserving update compatibility for existing streaming pipelines via TableDestinationCoderV3 when range partitioning is not enabled.
🔍 General Feedback
- The backward compatibility design around
TableDestinationCoderV3vsTableDestinationCoderV4and fail-fast validation inPrepareWriteis well thought out. - In
TableDestination,equals()andhashCode()omitjsonClustering, which causes destination collisions whenTableDestinationis used as a map/grouping key and breaksCoderPropertiesequality checks when clustering is populated.
💡 Tip: Comment /gemini review on this pull request to trigger a new Gemini code review.
💬 Inline Findings
sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/TableDestination.java(line 274): 🟠 High:equals(andhashCodeon line 280) omitsthis.jsonClustering. BecauseTableDestinationis used as aMapkey inWriteBundlesToFilesandWritePartitionand as aGroupByKeykey across BigQuery write transforms, twoTableDestinationinstances with the sametableSpecbut differentjsonClusteringconfigurations will be treated as equal. Additionally,TableDestinationCoderV3andTableDestinationCoderV4encodejsonClustering, so omitting it fromequals/hashCodeviolates Beam'sCoderequality contract.
Please include Objects.equals(this.jsonClustering, other.jsonClustering) in equals and jsonClustering in Objects.hash(...).
&& Objects.equals(this.jsonClustering, other.jsonClustering) && Objects.equals(this.jsonRangePartitioning, other.jsonRangePartitioning);
sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/TableDestination.java(line 280): 🟠 High: IncludejsonClusteringinhashCode()to matchequals()and the fields serialized byTableDestinationCoderV3/TableDestinationCoderV4.
return Objects.hash(tableSpec, tableDescription, jsonTimePartitioning, jsonClustering, jsonRangePartitioning);
|
On the automated review's BEAM-5191 (2018) added clustering without adding it to The I'd rather not change grouping for existing clustering users in this PR. If reviewers want it changed, I'll open a follow-up issue. |
|
Checks are failing. Will not request review until checks are succeeding. If you'd like to override that behavior, comment |
|
assign set of reviewers The one failing check, |
|
Assigning reviewers: R: @Abacn for label java. Note: If you would like to opt out of this review, comment Available commands:
The PR bot will only process comments in the main thread (not review comments). |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #40790 +/- ##
===========================================
- Coverage 80.04% 0 -80.05%
===========================================
Files 490 0 -490
Lines 82916 0 -82916
===========================================
- Hits 66373 0 -66373
+ Misses 16543 0 -16543
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
withRangePartitioning() with no arguments on a single table only turned on the V4 coder, so BigQuery created an unpartitioned table without an error. The write now fails at construction and says to pass a RangePartitioning. A TableDestination with both time and range partitioning used to fail later, inside BigQuery. The constructor now throws IllegalArgumentException.
|
/gemini review |
Fixes #27069.
Adds integer-range partitioning to
BigQueryIO.Writein the Java SDK. Python already supports it throughadditional_bq_parameters.Usage
With
to(SerializableFunction)orto(DynamicDestinations), set theRangePartitioningon each returnedTableDestinationand callwithRangePartitioning()with no arguments. A customDynamicDestinationsmust also returnTableDestinationCoderV4fromgetDestinationCoder().Update compatibility: drain and restart required
Turning on range partitioning switches the destination coder to a new
TableDestinationCoderV4. V4 writes the V3 encoding followed by the range partitioning, and it can't read state written by V2 or V3. A running pipeline can't be updated in place to turn this on. Drain it and start a new one.Pipelines that don't call
withRangePartitioningkeepTableDestinationCoderV2orV3, so their encoding is unchanged and in-place updates keep working. V4 is registered in the Dataflow runner'sDefaultCoderCloudObjectTranslatorRegistrar.Changes
TableDestinationcarries an optional range partitioning as a JSON string, the same way it stores time partitioning and clustering.CreateTableHelpers) and load jobs (WriteTables,UpdateSchemaDestination) pass range partitioning to BigQuery. This coversFILE_LOADS,STREAMING_INSERTSand the Storage Write API.FILE_LOADStemp tables copy the range partitioning of an existing destination table, so copy jobs into it succeed. This is the Java counterpart of Preserve partitioning on temp FILE_LOADS tables #38833.PrepareWritefails with an error if a destination has range partitioning but the destination coder would drop it. Without the check, the table would be created without partitioning and no error.withTimePartitioningandwithRangePartitioningfails at construction, since a BigQuery table can have only one.BigQueryIOTranslationaddsjson_range_partitioningto the transform upgrade schema, read only when upgrading from 2.78.0 or later. If this misses the 2.78.0 cut, I'll move that gate and theCHANGES.mdentry to 2.79.0.Tests
TableDestinationCoderV4Test, plus new cases inBigQueryIOWriteTestandBigQueryIOTranslationTest.BigQueryRangePartitioningITwrites to real BigQuery: a single table, a table function with clustering, the Storage Write API, and temp tables into an existing range-partitioned table. It runs inbeam_PreCommit_Java_GCP_IO_Direct_BigQuery. I haven't run it against my own project, so that job is its first real run.