Flink CDC系列之:Doris 模式工具类DorisSchemaUtils
这是一个 Doris 模式工具类,专门用于处理 Flink CDC 到 Doris 数据同步时的自动分区配置。
java
public class DorisSchemaUtils
这个工具类主要负责根据配置信息为 Doris 表生成自动分区策略,特别适用于时间序列数据的自动分区管理。
核心常量定义
java
public static final String DEFAULT_DATE = "1970-01-01";
public static final String DEFAULT_DATETIME = "1970-01-01 00:00:00";
public static final String INVALID_OR_MISSING_DATATIME = "0000-00-00 00:00:00";
日期常量:用于处理默认日期和无效日期值。
核心方法详解
getPartitionInfo() - 获取分区信息
这是工具类的核心方法,根据配置生成 Doris 表的分区策略:
java
public static Tuple2<String, String> getPartitionInfo(
Configuration config, Schema schema, TableId tableId) {
参数说明:
- config:Flink CDC 配置
- schema:表结构定义
- tableId:表标识
返回值:Tuple2<分区键, 分区单位>,如 ("create_time", "DAY")
方法执行流程
检查自动分区配置
java
Map<String, String> autoPartitionProperties =
DorisDataSinkOptions.getPropertiesByPrefix(
config, TABLE_CREATE_AUTO_PARTITION_PROPERTIES_PREFIX);
if (autoPartitionProperties.isEmpty()) {
return null; // 没有配置自动分区,返回null
}
作用:从配置中提取所有以 table.create.auto-partition. 为前缀的配置项。
表包含/排除检查
java
if (isExcluded(autoPartitionProperties, tableId)
|| !isIncluded(autoPartitionProperties, tableId)) {
return null; // 表被排除或不在包含列表中,返回null
}
获取分区键
java
String partitionKey =
getPartitionProperty(
autoPartitionProperties,
tableId,
TABLE_CREATE_PARTITION_KEY,
TABLE_CREATE_DEFAULT_PARTITION_KEY);
if (partitionKey == null || !schema.getColumn(partitionKey).isPresent()) {
return null; // 分区键不存在于表结构中
}
调用 getPartitionProperty 方法,从配置(autoPartitionProperties)中尝试获取指定的分区键。
参数说明:
- autoPartitionProperties:存储分区相关配置的容器(如 Map<String, String>)。
- tableId:目标表的标识符。
- TABLE_CREATE_PARTITION_KEY:明确指定分区键的配置项。
- TABLE_CREATE_DEFAULT_PARTITION_KEY:默认分区键的配置项(当前键不存在时可能使用)。
验证分区键的有效性
java
if (partitionKey == null || !schema.getColumn(partitionKey).isPresent()) {
return null; // 分区键不存在于表结构中
}
- 条件1:partitionKey == null
- 表示配置中未定义任何分区键。
- 条件2:!schema.getColumn(partitionKey).isPresent()
- 表示分区键的列名在表结构(schema)中不存在。
- 如果任一条件满足,则返回 null,表示无法进行分区。
获取分区单位
java
String partitionUnit =
getPartitionProperty(
autoPartitionProperties,
tableId,
TABLE_CREATE_PARTITION_UNIT,
TABLE_CREATE_DEFAULT_PARTITION_UNIT);
if (partitionUnit == null) {
return null;
}
验证数据类型并返回
java
DataType dataType = schema.getColumn(partitionKey).get().getType();
从表结构(schema)中获取分区键(partitionKey)对应的列。
通过 getType() 获取该列的数据类型(如 INT、STRING、TIMESTAMP 等)。
验证数据类型并返回结果
java
return isValidDataType(dataType) ? new Tuple2<>(partitionKey, partitionUnit) : null;
调用 isValidDataType(dataType) 检查该数据类型是否允许作为分区键。
如果有效:返回一个 Tuple2 对象,包含:
- partitionKey(分区键列名)
- partitionUnit(分区单位,如按天、按月等)
- 如果无效:返回 null,表示该列不能作为分区键。
辅助方法详解
表排除检查 isExcluded()
java
private static boolean isExcluded(Map<String, String> properties, TableId tableId) {
String excludes = properties.get(TABLE_CREATE_PARTITION_EXCLUDE);
if (!StringUtils.isNullOrWhitespaceOnly(excludes)) {
Selectors selectExclude =
new Selectors.SelectorsBuilder().includeTables(excludes).build();
return selectExclude.isMatch(tableId);
}
return false;
}
作用:检查表是否在排除列表中。
表包含检查 isIncluded()
java
private static boolean isIncluded(Map<String, String> properties, TableId tableId) {
String includes = properties.get(TABLE_CREATE_PARTITION_INCLUDE);
if (!StringUtils.isNullOrWhitespaceOnly(includes)) {
Selectors selectInclude =
new Selectors.SelectorsBuilder().includeTables(includes).build();
return selectInclude.isMatch(tableId);
}
return true; // 默认包含所有表
}
作用:检查表是否在包含列表中。
获取分区属性 getPartitionProperty()
java
private static String getPartitionProperty(
Map<String, String> properties,
TableId tableId,
String specificKey,
String defaultKey) {
String key = properties.get(tableId.identifier() + "." + specificKey);
return StringUtils.isNullOrWhitespaceOnly(key) ? properties.get(defaultKey) : key;
}
StringUtils.isNullOrWhitespaceOnly 是一个工具方法,用于检查字符串是否为 null 或仅包含空白字符。以下是详细解释:
方法功能
- 作用:判断输入的字符串是否为 null 或仅由空白字符(如空格、制表符、换行符等)组成。
- 返回值:
- true:字符串为 null 或仅包含空白字符。
- false:字符串包含至少一个非空白字符。
优先级:先查找表特定的配置,找不到则使用默认配置。
数据类型验证 isValidDataType()
java
private static boolean isValidDataType(DataType dataType) {
return dataType instanceof LocalZonedTimestampType
|| dataType instanceof TimestampType
|| dataType instanceof ZonedTimestampType
|| dataType instanceof DateType;
}
支持的数据类型:只允许时间/日期类型作为分区键。
配置示例
Flink CDC 配置示例
java
# 自动分区全局配置
table.create.auto-partition.partition-key=create_time
table.create.auto-partition.partition-unit=DAY
# 表包含/排除配置
table.create.auto-partition.include=database1.table1,database1.table2
table.create.auto-partition.exclude=database1.temp_table
# 表特定配置(优先级更高)
table.create.auto-partition.database1.table1.partition-key=update_time
table.create.auto-partition.database1.table1.partition-unit=MONTH
在 Flink CDC Pipeline 中使用
java
mysql-sync-database \
--database source_db \
--sink-conf connector=doris \
--sink-conf fenodes=fe1:8030 \
--sink-conf username=user \
--sink-conf password=pass \
--table-create-auto-partition.partition-key=create_time \
--table-create-auto-partition.partition-unit=DAY \
--table-create-auto-partition.include="inventory.orders,inventory.products"
生成的 Doris DDL 示例
基于这个工具类的输出,会生成类似这样的 Doris 建表语句:
sql
-- 自动生成的分区表
CREATE TABLE `target_db`.`orders` (
`id` BIGINT,
`order_no` VARCHAR(100),
`create_time` DATETIME,
`amount` DECIMAL(10,2)
)
PARTITION BY RANGE(`create_time`)()
DISTRIBUTED BY HASH(`id`) BUCKETS 10
PROPERTIES (
"dynamic_partition.enable" = "true",
"dynamic_partition.time_unit" = "DAY",
"dynamic_partition.start" = "-30",
"dynamic_partition.end" = "3",
"dynamic_partition.prefix" = "p",
"dynamic_partition.buckets" = "10"
);
设计特点
- 灵活的配置策略
全局默认配置:适用于所有表
表特定配置:为特定表覆盖全局配置
包含/排除机制:精确控制哪些表启用自动分区
使用场景
这个工具类主要用在以下场景:
- 时间序列数据自动分区:如日志、监控数据按天分区
- 大数据量表管理:自动维护历史数据分区
- CDC 数据同步:将源库的表结构映射到 Doris 的自动分区表
- 多租户数据隔离:不同表使用不同的分区策略
总结:这个 DorisSchemaUtils 工具类为 Flink CDC 到 Doris 的数据同步提供了强大的自动分区管理能力,通过灵活的配置机制和严格的数据类型验证,确保生成的 Doris 表具有合理且高效的分区结构。