-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Flink: Integrate ConvertEqualityDeletes with IcebergSink #17142
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -163,6 +163,20 @@ INSERT INTO tableName /*+ OPTIONS('upsert-enabled'='true') */ | |
| | shred-variants | Table write.parquet.shred-variants | Overrides this table's shred variants for this write | | ||
| | variant-inference-buffer-size | Table write.parquet.variant-inference-buffer-size | Overrides this table's variant inference buffer size for this write | | ||
|
|
||
| #### Post-commit maintenance options | ||
|
|
||
| `IcebergSink` can run [table maintenance](flink-maintenance.md#icebergsink-with-post-commit-integration) | ||
| after each commit. The enable flags are listed below; see the maintenance docs for the full per-task | ||
| option set. | ||
|
|
||
| | Flink option | Default | Description | | ||
| |--------------|---------|-------------| | ||
| | flink-maintenance.rewrite.enabled | false | Compact data files after commit | | ||
| | flink-maintenance.expire-snapshots.enabled | false | Expire snapshots after commit | | ||
| | flink-maintenance.delete-orphan-files.enabled | false | Delete orphan files after commit | | ||
| | flink-maintenance.convert-equality-deletes.enabled | false | Convert equality deletes to deletion vectors after commit (requires equality fields and format version >= 3) | | ||
| | flink-maintenance.convert-equality-deletes.target-branch | Write branch | Branch the converted DVs are committed to; defaults to the write branch (in-place conversion) | | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we want this here? |
||
|
|
||
| #### Range distribution statistics type | ||
|
|
||
| Config value is a enum type: `Map`, `Sketch`, `Auto`. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -375,6 +375,18 @@ IcebergSink.forRowData(dataStream) | |
| .append(); | ||
| ``` | ||
|
|
||
| `convertEqualityDeletes()` converts equality deletes to deletion vectors. Unlike the other tasks, it requires equality field columns (upsert or CDC writes) and a table with format version >= 3. By default, it converts in place on the write branch: | ||
|
|
||
| ```java | ||
| IcebergSink.forRowData(dataStream) | ||
| .table(table) | ||
| .tableLoader(tableLoader) | ||
| .upsert(true) | ||
| .equalityFieldColumns(List.of("id")) | ||
| .convertEqualityDeletes() | ||
| .append(); | ||
| ``` | ||
|
|
||
| ##### Config | ||
|
|
||
| All maintenance tasks are configured through string properties: | ||
|
|
@@ -386,6 +398,8 @@ Map<String, String> flinkConf = new HashMap<>(); | |
| flinkConf.put("flink-maintenance.rewrite.enabled", "true"); | ||
| flinkConf.put("flink-maintenance.expire-snapshots.enabled", "true"); | ||
| flinkConf.put("flink-maintenance.delete-orphan-files.enabled", "true"); | ||
| // Requires equality field columns (upsert or CDC) and a table with format version >= 3. | ||
| flinkConf.put("flink-maintenance.convert-equality-deletes.enabled", "true"); | ||
|
|
||
| // Configure rewrite data files | ||
| flinkConf.put("flink-maintenance.rewrite.max-bytes", "1073741824"); | ||
|
|
@@ -397,6 +411,10 @@ flinkConf.put("flink-maintenance.expire-snapshots.max-snapshot-age-seconds", "60 | |
| // Configure delete orphan files | ||
| flinkConf.put("flink-maintenance.delete-orphan-files.min-age-seconds", "259200"); | ||
|
|
||
| // Configure convert equality deletes. Converts in place on the write branch by default; | ||
| // set a target branch to instead promote the converted deletion vectors there. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: weird sentence, possible rewording: |
||
| flinkConf.put("flink-maintenance.convert-equality-deletes.target-branch", "main"); | ||
|
|
||
| // Configure JDBC lock settings (deprecated, lock configuration is no longer required for a single Flink job) | ||
| flinkConf.put("flink-maintenance.lock.type", "jdbc"); | ||
| flinkConf.put("flink-maintenance.lock.jdbc.uri", "jdbc:postgresql://localhost:5432/iceberg"); | ||
|
|
@@ -419,6 +437,8 @@ SET 'table.exec.iceberg.use.v2.sink' = 'true'; | |
| SET 'flink-maintenance.rewrite.enabled' = 'true'; | ||
| SET 'flink-maintenance.expire-snapshots.enabled' = 'true'; | ||
| SET 'flink-maintenance.delete-orphan-files.enabled' = 'true'; | ||
| -- Requires equality field columns (upsert) and a table with format version >= 3 | ||
| SET 'flink-maintenance.convert-equality-deletes.enabled' = 'true'; | ||
|
|
||
| -- Configure rewrite data files | ||
| SET 'flink-maintenance.rewrite.max-bytes' = '1073741824'; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -398,6 +398,32 @@ To use SinkV2 based implementation, replace `FlinkSink` with `IcebergSink` in th | |
| - The `RANGE` distribution mode is not yet available for the `IcebergSink` | ||
| - When using `IcebergSink` use `uidSuffix` instead of the `uidPrefix` | ||
|
|
||
| ### Post-commit table maintenance | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we only make this part only in flink-maintenance.md? |
||
|
|
||
| `IcebergSink` can run [table maintenance](flink-maintenance.md#icebergsink-with-post-commit-integration) | ||
| tasks automatically after each commit, so a separate maintenance job is not required. Enable them with | ||
| builder methods (or the equivalent `flink-maintenance.*` write options): | ||
|
|
||
| - `rewriteDataFiles()` compacts small data files | ||
| - `expireSnapshots()` expires old snapshots | ||
| - `deleteOrphanFiles()` removes unreferenced files | ||
| - `convertEqualityDeletes()` converts equality deletes to deletion vectors (requires equality fields | ||
| and table format version >= 3) | ||
|
|
||
| ```java | ||
| IcebergSink.forRowData(dataStream) | ||
| .table(table) | ||
| .tableLoader(tableLoader) | ||
| .upsert(true) | ||
| .equalityFieldColumns(List.of("id")) | ||
| .rewriteDataFiles() | ||
| .convertEqualityDeletes() | ||
| .append(); | ||
| ``` | ||
|
|
||
| See [IcebergSink with Post-Commit Integration](flink-maintenance.md#icebergsink-with-post-commit-integration) | ||
| for the full options, locking, and the `convertEqualityDeletes` staging/target-branch setup. | ||
|
|
||
| ## Flink Dynamic Iceberg Sink | ||
|
|
||
| The Flink Dynamic Iceberg Sink (Dynamic Sink) allows: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, | ||
| * software distributed under the License is distributed on an | ||
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| * KIND, either express or implied. See the License for the | ||
| * specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
| package org.apache.iceberg.flink.maintenance.api; | ||
|
|
||
| import java.util.Map; | ||
| import org.apache.flink.configuration.ConfigOption; | ||
| import org.apache.flink.configuration.ConfigOptions; | ||
| import org.apache.flink.configuration.ReadableConfig; | ||
| import org.apache.iceberg.Table; | ||
| import org.apache.iceberg.flink.FlinkConfParser; | ||
|
|
||
| public class ConvertEqualityDeletesConfig { | ||
| public static final String PREFIX = FlinkMaintenanceConfig.PREFIX + "convert-equality-deletes."; | ||
|
|
||
| public static final String TARGET_BRANCH = PREFIX + "target-branch"; | ||
| public static final ConfigOption<String> TARGET_BRANCH_OPTION = | ||
| ConfigOptions.key(TARGET_BRANCH) | ||
| .stringType() | ||
| .noDefaultValue() | ||
| .withDescription( | ||
| "The branch where converted data files and deletion vectors are committed. " | ||
| + "Defaults to the sink's write branch, i.e. an in-place conversion."); | ||
|
|
||
| public static final String SCHEDULE_ON_COMMIT_COUNT = PREFIX + "schedule.commit-count"; | ||
| public static final ConfigOption<Integer> SCHEDULE_ON_COMMIT_COUNT_OPTION = | ||
| ConfigOptions.key(SCHEDULE_ON_COMMIT_COUNT) | ||
| .intType() | ||
| .defaultValue(1) | ||
| .withDescription( | ||
| "The number of commits after which to trigger a new equality delete conversion."); | ||
|
|
||
| public static final String SCHEDULE_ON_INTERVAL_SECOND = PREFIX + "schedule.interval-second"; | ||
| public static final ConfigOption<Long> SCHEDULE_ON_INTERVAL_SECOND_OPTION = | ||
| ConfigOptions.key(SCHEDULE_ON_INTERVAL_SECOND) | ||
| .longType() | ||
| .noDefaultValue() | ||
| .withDescription( | ||
| "The time interval (in seconds) between two consecutive equality delete conversions."); | ||
|
|
||
| private final FlinkConfParser confParser; | ||
|
|
||
| public ConvertEqualityDeletesConfig( | ||
| Table table, Map<String, String> writeOptions, ReadableConfig readableConfig) { | ||
| this.confParser = new FlinkConfParser(table, writeOptions, readableConfig); | ||
| } | ||
|
|
||
| /** Gets the target branch, or null to convert in place on the sink's write branch. */ | ||
| public String targetBranch() { | ||
| return confParser | ||
| .stringConf() | ||
| .option(TARGET_BRANCH) | ||
| .flinkConfig(TARGET_BRANCH_OPTION) | ||
| .parseOptional(); | ||
| } | ||
|
|
||
| /** Gets the number of commits that trigger a conversion. */ | ||
| public int scheduleOnCommitCount() { | ||
| return confParser | ||
| .intConf() | ||
| .option(SCHEDULE_ON_COMMIT_COUNT) | ||
| .flinkConfig(SCHEDULE_ON_COMMIT_COUNT_OPTION) | ||
| .defaultValue(SCHEDULE_ON_COMMIT_COUNT_OPTION.defaultValue()) | ||
| .parse(); | ||
| } | ||
|
|
||
| /** Gets the time interval (in seconds) between conversions, or null when not set. */ | ||
| public Long scheduleOnIntervalSecond() { | ||
| return confParser | ||
| .longConf() | ||
| .option(SCHEDULE_ON_INTERVAL_SECOND) | ||
| .flinkConfig(SCHEDULE_ON_INTERVAL_SECOND_OPTION) | ||
| .parseOptional(); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: The config option itself has no default value. Maybe it would be less confusing to keep this table in sync with that and put
nullto theDefaulttable col (based on the read option table) and rephrase the description that something like "if not specified, the write branch will be used (in-place conversion)"