org.apache.paimon.flink.action.MergeIntoActionFactory Maven / Gradle / Ivy
The newest version!
/*
* 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.paimon.flink.action;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/** Factory to create {@link MergeIntoAction}. */
public class MergeIntoActionFactory implements ActionFactory {
public static final String IDENTIFIER = "merge_into";
public static final String MATCHED_UPSERT = "matched-upsert";
public static final String NOT_MATCHED_BY_SOURCE_UPSERT = "not-matched-by-source-upsert";
public static final String MATCHED_DELETE = "matched-delete";
public static final String NOT_MATCHED_BY_SOURCE_DELETE = "not-matched-by-source-delete";
public static final String NOT_MATCHED_INSERT = "not-matched-insert";
private static final String TARGET_AS = "target_as";
private static final String SOURCE_SQL = "source_sql";
private static final String SOURCE_TABLE = "source_table";
private static final String ON = "on";
private static final String MERGE_ACTIONS = "merge_actions";
private static final String MATCHED_UPSERT_SET = "matched_upsert_set";
private static final String MATCHED_UPSERT_CONDITION = "matched_upsert_condition";
private static final String NOT_MATCHED_BY_SOURCE_UPSERT_SET =
"not_matched_by_source_upsert_set";
private static final String NOT_MATCHED_BY_SOURCE_UPSERT_CONDITION =
"not_matched_by_source_upsert_condition";
private static final String MATCHED_DELETE_CONDITION = "matched_delete_condition";
private static final String NOT_MATCHED_BY_SOURCE_DELETE_CONDITION =
"not_matched_by_source_delete_condition";
private static final String NOT_MATCHED_INSERT_VALUES = "not_matched_insert_values";
private static final String NOT_MATCHED_INSERT_CONDITION = "not_matched_insert_condition";
@Override
public String identifier() {
return IDENTIFIER;
}
@Override
public Optional create(MultipleParameterToolAdapter params) {
MergeIntoAction action =
new MergeIntoAction(
params.getRequired(DATABASE),
params.getRequired(TABLE),
catalogConfigMap(params));
if (params.has(TARGET_AS)) {
action.withTargetAlias(params.get(TARGET_AS));
}
if (params.has(SOURCE_SQL)) {
Collection sourceSqls = params.getMultiParameter(SOURCE_SQL);
action.withSourceSqls(sourceSqls.toArray(new String[0]));
}
action.withSourceTable(params.getRequired(SOURCE_TABLE));
action.withMergeCondition(params.getRequired(ON));
List actions =
Arrays.stream(params.get(MERGE_ACTIONS).split(","))
.map(String::trim)
.collect(Collectors.toList());
if (actions.contains(MATCHED_UPSERT)) {
action.withMatchedUpsert(
params.get(MATCHED_UPSERT_CONDITION), params.getRequired(MATCHED_UPSERT_SET));
}
if (actions.contains(NOT_MATCHED_BY_SOURCE_UPSERT)) {
action.withNotMatchedBySourceUpsert(
params.get(NOT_MATCHED_BY_SOURCE_UPSERT_CONDITION),
params.getRequired(NOT_MATCHED_BY_SOURCE_UPSERT_SET));
}
if (actions.contains(MATCHED_DELETE)) {
action.withMatchedDelete(params.get(MATCHED_DELETE_CONDITION));
}
if (actions.contains(NOT_MATCHED_BY_SOURCE_DELETE)) {
action.withNotMatchedBySourceDelete(params.get(NOT_MATCHED_BY_SOURCE_DELETE_CONDITION));
}
if (actions.contains(NOT_MATCHED_INSERT)) {
action.withNotMatchedInsert(
params.get(NOT_MATCHED_INSERT_CONDITION),
params.getRequired(NOT_MATCHED_INSERT_VALUES));
}
action.validate();
return Optional.of(action);
}
@Override
public void printHelp() {
System.out.println("Action \"merge_into\" simulates the \"MERGE INTO\" syntax.");
System.out.println();
System.out.println("Syntax:");
System.out.println(
" merge_into --warehouse \n"
+ " --database \n"
+ " --table \n"
+ " [--target_as ]\n"
+ " [--source_sql ...]\n"
+ " --source_table \n"
+ " --on \n"
+ " --merge_actions \n"
+ " --matched_upsert_condition \n"
+ " --matched_upsert_set \n"
+ " --matched_delete_condition \n"
+ " --not_matched_insert_condition \n"
+ " --not_matched_insert_values \n"
+ " --not_matched_by_source_upsert_condition \n"
+ " --not_matched_by_source_upsert_set \n"
+ " --not_matched_by_source_delete_condition ");
System.out.println(" matched_upsert_set format:");
System.out.println(
" col=.col | expression [, ...] (do not add '.' before 'col')");
System.out.println(
" * (upsert with all source cols; require target table's schema is equal to source's)");
System.out.println(" not_matched_upsert_set format:");
System.out.println(" col=expression (cannot use source table's col)");
System.out.println(" insert_values format:");
System.out.println(
" col1,col2,...,col_end (must specify values of all columns; can use .col or expression)");
System.out.println(
" * (insert with all source cols; require target table's schema is equal to source's)");
System.out.println(
" not_matched_condition: cannot use target table's columns to construct condition expression.");
System.out.println(
" not_matched_by_source_condition: cannot use source table's columns to construct condition expression.");
System.out.println(" alternative arguments:");
System.out.println(" --path to represent the table path.");
System.out.println();
System.out.println("Note: ");
System.out.println(" 1. Target table must has primary keys.");
System.out.println(
" 2. All conditions, set changes and values should use Flink SQL syntax. Please quote them with \" to escape special characters.");
System.out.println(
" 3. You can pass sqls by --source_sql to config environment and create source table at runtime");
System.out.println(" 4. Target alias cannot be duplicated with existed table name.");
System.out.println(
" 5. If the source table is not in the current catalog and current database, "
+ "the source_table_name must be qualified (database.table or catalog.database.table if in different catalog).");
System.out.println(" 6. At least one merge action must be specified.");
System.out.println(" 7. How to determine the changed rows with different \"matched\":");
System.out.println(
" matched: changed rows are from target table and each can match a source table row "
+ "based on merge_condition and optional matched_condition.");
System.out.println(
" not_matched: changed rows are from source table and all rows cannot match any target table row "
+ "based on merge_condition and optional not_matched_condition.");
System.out.println(
" not_matched_by_source: changed rows are from target table and all row cannot match any source table row "
+ "based on merge_condition and optional not_matched_by_source_condition.");
System.out.println(
" 8. If both matched_upsert and matched_delete actions are present, their conditions must both be present too "
+ "(same to not_matched_by_source_upsert and not_matched_by_source_delete). Otherwise, all conditions are optional.");
System.out.println();
System.out.println("Examples:");
System.out.println(
" merge_into --path hdfs:///path/to/T\n"
+ " --source_table S\n"
+ " --on \"T.k = S.k\"\n"
+ " --merge_actions matched-upsert\n"
+ " --matched_upsert_condition \"T.v <> S.v\"\n"
+ " --matched_upsert_set \"v = S.v\"");
System.out.println(
" It will find matched rows of target table that meet condition (T.k = S.k), then update T.v with S.v where (T.v <> S.v).");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy