4. Flink Table & SQL API 入门:动态表概念、TableEnvironment创建、Kafka流表定义、简单SQL查询
在贷后预警场景中,实时数据流(如还款流水、客户行为事件)需要被持续计算。Flink Table & SQL API 提供了声明式的编程接口,让开发者可以用 SQL 表达流处理逻辑,大幅降低开发门槛。本章将围绕动态表的核心概念、环境创建、Kafka 流表定义以及基础 SQL 查询展开,为后续预警规则实现打下基础。
4.1 动态表(Dynamic Table)核心概念
传统数据库中的表是静态的,数据插入后不会自动变化。Flink 中的动态表则随时间不断演化——新数据到达时,表的内容会持续追加或更新。动态表是连接流处理与 SQL 的桥梁:
- 流 → 动态表:将无界数据流转换为带 Schema 的动态表,每条记录对应表的一行。
- 动态表 → 流:对动态表执行连续查询(Continuous Query),结果也是一个动态表,可再转换为 DataStream 输出。
- 查询连续性:SQL 查询在动态表上持续运行,每次数据变更都会触发结果更新,实现实时计算。
理解要点:动态表不是一次性快照,而是随时间变化的视图。在贷后预警中,每笔还款事件到达时,动态表会立即新增一行,SQL 查询(如 SUM、COUNT)的结果也随之实时刷新。
4.2 TableEnvironment 创建
TableEnvironment 是 Flink Table & SQL API 的入口,负责注册表、执行 SQL 查询、管理 UDF 等。根据执行环境的不同,创建方式分为两种:
| 环境类型 | 适用场景 | 创建方式 |
|---|---|---|
| StreamTableEnvironment | 流处理作业(贷后预警实时计算) | StreamTableEnvironment.create(StreamExecutionEnvironment) |
| TableEnvironment | 批处理或流批一体 | TableEnvironment.create(EnvironmentSettings.inStreamingMode()) |
在贷后预警项目中,我们使用流处理模式,推荐通过 EnvironmentSettings 创建,以便统一配置 Planner 和运行时行为:
// 1. 创建 StreamExecutionEnvironment
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// 2. 设置 EnvironmentSettings(使用 Blink Planner,流模式)
EnvironmentSettings settings = EnvironmentSettings.newInstance()
.inStreamingMode()
.build();
// 3. 创建 StreamTableEnvironment
StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env, settings);
关键配置说明:
inStreamingMode():明确指定流处理模式,确保动态表语义正确。build():构建不可变的 Settings 对象,传递给 TableEnvironment。- Blink Planner 是 Flink 1.14+ 的默认优化器,支持更丰富的 SQL 语法和性能优化。
4.3 Kafka 流表定义
贷后预警的实时数据通常来自 Kafka。Flink 通过 Kafka Connector 将 Topic 映射为动态表,定义时需要指定 Schema、连接参数以及 Format(如 JSON、CSV)。
以下示例定义了一个名为 repayment_events 的 Kafka 流表,用于接收还款事件:
tableEnv.executeSql(
"CREATE TABLE repayment_events (" +
" event_time STRING, " +
" customer_id STRING, " +
" loan_id STRING, " +
" amount DECIMAL(10, 2), " +
" status STRING, " +
" proc_time AS PROCTIME() " + // 处理时间属性
") WITH (" +
" 'connector' = 'kafka', " +
" 'topic' = 'repayment-topic', " +
" 'properties.bootstrap.servers' = 'localhost:9092', " +
" 'properties.group.id' = 'flink-warning-group', " +
" 'scan.startup.mode' = 'latest-offset', " +
" 'format' = 'json', " +
" 'json.fail-on-missing-field' = 'false', " +
" 'json.ignore-parse-errors' = 'true' " +
")"
);
| 参数 | 说明 | 贷后预警推荐值 |
|---|---|---|
connector |
连接器类型 | kafka |
topic |
Kafka Topic 名称 | 按业务命名,如 repayment-topic |
properties.bootstrap.servers |
Kafka 集群地址 | 生产环境使用集群地址 |
scan.startup.mode |
消费起始位置 | latest-offset(只处理新数据) |
format |
消息格式 | json(通用、易解析) |
json.fail-on-missing-field |
字段缺失是否报错 | false(容错处理) |
注意事项:
- Kafka 表定义中的字段名必须与 JSON 消息中的 key 完全匹配(区分大小写)。
PROCTIME()是处理时间属性,表示数据到达 Flink 的时刻;若需事件时间,需额外定义 Watermark。- 生产环境中建议开启
json.ignore-parse-errors避免单条坏数据导致作业失败。
4.4 简单 SQL 查询:SELECT、WHERE、GROUP BY
定义好 Kafka 流表后,即可使用 SQL 进行实时查询。以下展示三种基础操作:
4.4.1 SELECT 投影与字段过滤
// 查询所有字段
Table result = tableEnv.sqlQuery("SELECT * FROM repayment_events");
// 查询特定字段,并重命名
Table selected = tableEnv.sqlQuery(
"SELECT customer_id, amount AS repay_amount, status FROM repayment_events"
);
4.4.2 WHERE 条件过滤
// 筛选逾期状态(status = 'OVERDUE')且金额大于 1000 的事件
Table filtered = tableEnv.sqlQuery(
"SELECT customer_id, amount, event_time " +
"FROM repayment_events " +
"WHERE status = 'OVERDUE' AND amount > 1000"
);
4.4.3 GROUP BY 聚合统计
// 按客户分组,统计每个客户的累计还款金额和事件次数
Table aggregated = tableEnv.sqlQuery(
"SELECT customer_id, " +
" SUM(amount) AS total_repay, " +
" COUNT(*) AS event_count " +
"FROM repayment_events " +
"GROUP BY customer_id"
);
流式 GROUP BY 说明:在动态表上执行
GROUP BY 会产生一个持续更新的聚合结果表。每来一条新数据,Flink 都会更新对应分组的 SUM/COUNT 值。贷后预警中常用此方式实时计算客户累计逾期金额或还款次数。
4.5 完整示例:贷后预警简单查询
将上述知识点串联,实现一个完整的贷后预警 SQL 查询:从 Kafka 读取还款事件,过滤出逾期记录,按客户分组统计逾期总金额,并输出到控制台。
public class LoanWarningSQLDemo {
public static void main(String[] args) throws Exception {
// 1. 创建环境
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
EnvironmentSettings settings = EnvironmentSettings.newInstance().inStreamingMode().build();
StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env, settings);
// 2. 定义 Kafka 流表
tableEnv.executeSql(
"CREATE TABLE repayment_events (" +
" event_time STRING, " +
" customer_id STRING, " +
" loan_id STRING, " +
" amount DECIMAL(10, 2), " +
" status STRING, " +
" proc_time AS PROCTIME() " +
") WITH (" +
" 'connector' = 'kafka', " +
" 'topic' = 'repayment-topic', " +
" 'properties.bootstrap.servers' = 'localhost:9092', " +
" 'properties.group.id' = 'flink-warning-group', " +
" 'scan.startup.mode' = 'latest-offset', " +
" 'format' = 'json', " +
" 'json.fail-on-missing-field' = 'false', " +
" 'json.ignore-parse-errors' = 'true' " +
")"
);
// 3. 执行 SQL 查询:逾期预警统计
Table warningResult = tableEnv.sqlQuery(
"SELECT customer_id, " +
" SUM(amount) AS total_overdue_amount, " +
" COUNT(*) AS overdue_count " +
"FROM repayment_events " +
"WHERE status = 'OVERDUE' " +
"GROUP BY customer_id"
);
// 4. 将结果表转换为 DataStream 并打印
tableEnv.toChangelogStream(warningResult).print("预警结果");
// 5. 执行作业
env.execute("Flink 贷后预警 SQL 作业");
}
}
运行效果:当 Kafka Topic 中持续发送还款事件时,控制台会实时输出每个客户的逾期累计金额和次数。例如:
预警结果: +I[A001, 15000.00, 3] 表示客户 A001 累计逾期 15000 元,共 3 次。
4.6 本章小结
- 动态表是 Flink SQL 流处理的核心抽象,将无界流映射为持续变化的表。
- TableEnvironment 是 SQL 作业的入口,推荐使用
EnvironmentSettings创建流模式环境。 - Kafka 流表通过 DDL 定义,需指定 Schema、连接参数和 Format,支持 JSON 等常见格式。
- 简单 SQL 查询(SELECT、WHERE、GROUP BY)可直接应用于动态表,实现实时过滤与聚合。
- 贷后预警场景中,
WHERE status='OVERDUE'配合GROUP BY customer_id是最基础的预警统计模式。