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)的结果也随之实时刷新。
动态表与流的关系 动态表:流与 SQL 的桥梁 无界数据流 还款事件 客户行为 风控信号 持续到达,无终点 转换 动态表 Schema: 字段定义 | 时间戳 | 客户ID | 金额 | | 10:01 | A001 | 5000 | | 10:02 | A002 | 3000 | | 10:03 | A001 | 2000 | 随时间持续追加/更新 连续查询 结果动态表 实时聚合 客户A001: 7000 客户A002: 3000 结果持续刷新

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 值。贷后预警中常用此方式实时计算客户累计逾期金额或还款次数。
SQL 查询在动态表上的执行流程 SQL 查询在动态表上的执行流程 输入动态表 repayment_events 字段: customer_id 字段: amount, status 字段: event_time SQL 连续查询 SELECT ... FROM ... WHERE status='OVERDUE' GROUP BY customer_id 持续执行,每次数据触发 输出动态表 预警结果 customer_id total_overdue event_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 是最基础的预警统计模式。