Flink CDC系列之:Kafka CSV 序列化器CsvSerializationSchema

这是一个 CSV 序列化器,负责将 Flink CDC 事件转换为 CSV 格式的数据。

类概述

java 复制代码
public class CsvSerializationSchema implements SerializationSchema<Event>

这个类实现了 Flink 的 SerializationSchema 接口,专门用于将 CDC 事件序列化为 CSV 格式的字节数组。

核心属性

java 复制代码
private static final long serialVersionUID = 1L;

/**
 * A map of {@link TableId} and its {@link SerializationSchema} to serialize Debezium JSON data.
 */
private final Map<TableId, TableSchemaInfo> csvSerializers;  // 表结构缓存

private final ZoneId zoneId;  // 时区配置

private InitializationContext context;  // Flink 初始化上下文

构造函数

java 复制代码
public CsvSerializationSchema(ZoneId zoneId) {
    this.zoneId = zoneId;
    csvSerializers = new HashMap<>();
}

参数说明:

  • zoneId:处理时区敏感数据(如时间戳)

核心方法详解

open() - 初始化方法

java 复制代码
@Override
public void open(InitializationContext context) {
    this.context = context;
}

作用:Flink 在启动序列化器时调用,用于初始化资源。

serialize() - 主序列化方法

java 复制代码
@Override
public byte[] serialize(Event event) {
    if (event instanceof SchemaChangeEvent) {
        handleSchemaChangeEvent((SchemaChangeEvent) event);  // 处理Schema变更
        return null;
    }
    DataChangeEvent dataChangeEvent = (DataChangeEvent) event;
    return serializeDataChangeEvent(dataChangeEvent);        // 处理数据变更
}

Schema 变更事件处理

java 复制代码
private void handleSchemaChangeEvent(SchemaChangeEvent schemaChangeEvent) {
    Schema schema;
    if (event instanceof CreateTableEvent) {
        // 新建表:获取表结构
        CreateTableEvent createTableEvent = (CreateTableEvent) event;
        schema = createTableEvent.getSchema();
    } else {
        // 更新表结构:应用Schema变更
        schema = SchemaUtils.applySchemaChangeEvent(
                csvSerializers.get(schemaChangeEvent.tableId()).getSchema(),
                schemaChangeEvent);
    }
    
    // 构建CSV序列化器
    CsvRowDataSerializationSchema csvSerializer = buildSerializationForPrimaryKey(schema);
    try {
        csvSerializer.open(context);  // 初始化序列化器
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
    
    // 缓存表结构信息
    csvSerializers.put(
            schemaChangeEvent.tableId(),
            new TableSchemaInfo(
                    schemaChangeEvent.tableId(), schema, csvSerializer, zoneId));
}

数据变更事件处理

java 复制代码
private byte[] serializeDataChangeEvent(DataChangeEvent dataChangeEvent) {
    // 确定要序列化的数据
    RecordData recordData =
            dataChangeEvent.op().equals(OperationType.DELETE)
                    ? dataChangeEvent.before()  // 删除操作使用before数据
                    : dataChangeEvent.after();  // 其他操作使用after数据
    
    // 获取表结构信息
    TableSchemaInfo tableSchemaInfo = csvSerializers.get(dataChangeEvent.tableId());
    
    // 转换为RowData并序列化为CSV
    return tableSchemaInfo
            .getSerializationSchema()
            .serialize(tableSchemaInfo.getRowDataFromRecordData(recordData, true));
}

buildSerializationForPrimaryKey() - 构建CSV序列化器

java 复制代码
private CsvRowDataSerializationSchema buildSerializationForPrimaryKey(Schema schema) {
    // 构建包含表名和主键的字段数组
    DataField[] fields = new DataField[schema.primaryKeys().size() + 1];
    fields[0] = DataTypes.FIELD("TableId", DataTypes.STRING());  // 表标识字段
    
    // 添加所有主键字段
    for (int i = 0; i < schema.primaryKeys().size(); i++) {
        Column column = schema.getColumn(schema.primaryKeys().get(i)).get();
        fields[i + 1] = DataTypes.FIELD(column.getName(), column.getType());
    }
    
    // 构建数据类型
    DataType dataType = DataTypes.ROW(fields).notNull();
    LogicalType rowType = DataTypeUtils.toFlinkDataType(dataType).getLogicalType();
    
    // 创建CSV序列化器
    return new CsvRowDataSerializationSchema.Builder((RowType) rowType).build();
}

生成的 CSV 格式

数据结构

CSV 输出包含以下字段:

  • TableId:表标识(第一个字段)
  • 主键字段:所有主键列的值

示例输出

源表结构

java 复制代码
CREATE TABLE users (
    user_id BIGINT PRIMARY KEY,
    username VARCHAR(50),
    email VARCHAR(100),
    created_at TIMESTAMP
);

CREATE TABLE orders (
    order_id BIGINT PRIMARY KEY, 
    user_id BIGINT,
    amount DECIMAL(10,2),
    order_date DATE
);

CSV 输出示例

java 复制代码
# users 表数据
"users","1001"
"users","1002"

# orders 表数据  
"orders","5001"
"orders","5002"

完整数据 CSV 序列化

java 复制代码
// 可以修改为序列化所有字段
private CsvRowDataSerializationSchema buildSerializationForAllColumns(Schema schema) {
    DataField[] fields = new DataField[schema.getColumns().size() + 1];
    fields[0] = DataTypes.FIELD("TableId", DataTypes.STRING());
    for (int i = 0; i < schema.getColumns().size(); i++) {
        Column column = schema.getColumns().get(i);
        fields[i + 1] = DataTypes.FIELD(column.getName(), column.getType());
    }
    // ... 其余代码类似
}

这段代码定义了一个私有方法 buildSerializationForAllColumns,用于构建一个 CSV 行数据序列化模式。以下是逐行详细解释:

java 复制代码
private CsvRowDataSerializationSchema buildSerializationForAllColumns(Schema schema) {

声明一个私有的方法,返回类型为 CsvRowDataSerializationSchema,接受一个 Schema 对象作为参数。

java 复制代码
DataField[] fields = new DataField[schema.getColumns().size() + 1];

创建一个 DataField 数组,其长度比传入的 schema 中的列数多 1。这是因为除了原表的所有列外,还额外添加了一列(例如标识符或元数据)。

java 复制代码
fields[0] = DataTypes.FIELD("TableId", DataTypes.STRING());

将新数组的第一个元素设置为名为 "TableId" 的字段,数据类型为字符串。这通常用作表的唯一标识或其他元信息。

java 复制代码
for (int i = 0; i < schema.getColumns().size(); i++) {
    Column column = schema.getColumns().get(i);
    fields[i + 1] = DataTypes.FIELD(column.getName(), column.getType());
}

通过循环遍历 schema 中的所有列,从索引 1 开始填充 fields 数组。每个元素的名称和类型取自原始列的对应属性。

总结:这个 CsvSerializationSchema 是一个轻量级的序列化器,专门用于将 CDC 事件转换为包含表名和主键的 CSV 格式。它适用于需要轻量级变更通知、审计跟踪或主键级别数据同步的场景,通过只序列化关键信息来减少数据传输

相关推荐
最笨的羊羊2 小时前
Flink CDC系列之:Kafka的Debezium JSON 结构定义类DebeziumJsonStruct
kafka·debezium·flink cdc系列·debezium json·结构定义类·jsonstruct
最笨的羊羊2 小时前
Flink CDC系列之:Kafka JSON 序列化类型枚举
flink cdc系列·kafka json·序列化类型枚举
最笨的羊羊17 小时前
Flink CDC系列之:数据接收器工厂类DorisDataSinkFactory
doris·flink cdc系列·数据接收器工厂类·datasinkfactory
2501_941142132 天前
前端高性能优化与微前端架构设计在大型互联网系统中的实践经验分享
kafka
20岁30年经验的码农2 天前
Kafka 消息中间件实战指南
分布式·kafka·linq
yumgpkpm2 天前
腾讯云TBDS与CDH迁移常见问题有哪些?建议由CDH迁移到CMP 7.13 平台(类Cloudera CDP,如华为鲲鹏 ARM 版)
hive·hadoop·zookeeper·flink·spark·kafka·hbase
2501_941142132 天前
基于 Kotlin 构建移动端高并发后台服务与实时数据同步系统的架构设计与工程实践分享
kafka
yumgpkpm3 天前
数据可视化AI、BI工具,开源适配 Cloudera CMP 7.3(或类 CDP 的 CMP 7.13 平台,如华为鲲鹏 ARM 版)值得推荐?
人工智能·hive·hadoop·信息可视化·kafka·开源·hbase
Zhao·o3 天前
KafkaMQ采集指标日志
运维·中间件·kafka