Flink DataStream之min()与minBy(),max()与max之间的区别

Flink DataStream之min()与minBy(),max()与max之间的区别

min():获取的最小值,指定的field是最小,但不是最小的那条记录,后面的示例会清晰的显示。

minBy():获取的最小值,同时也是最小值的那条记录。

max()与maxBy()的区别也是一样。

那么下面来看示例:

public class MinOrMinByOperator {

    public static void main(String[] args) throws Exception {

        StreamExecutionEnvironment sEnv = StreamExecutionEnvironment.getExecutionEnvironment();
        sEnv.setParallelism(1);

        Properties p = new Properties();
        p.setProperty("bootstrap.servers", "localhost:9092");

        DataStreamSource<String> source = sEnv.addSource(new FlinkKafkaConsumer010<String>("student", new SimpleStringSchema(), p));

        source.print();

        WindowedStream<Student, String, TimeWindow> windowedStream = source
                .map(new MapFunction<String, Student>() {
                    @Override
                    public Student map(String value) throws Exceptio
<think>我们正在使用Flink SQL流式读取Paimon表,现在需要将SQL查询的结果转换为DataStream。 在Flink中,我们可以通过以下步骤实现: 1. 使用`TableEnvironment`执行SQL查询,得到一个`Table`对象。 2. 将`Table`对象转换为`DataStream`。 具体转换时,需要注意: - 流式读取的结果是持续变化的,因此我们使用`toDataStream`或`toChangelogStream`方法。 - 根据查询结果是否包含更新操作(如GROUP BY聚合)来决定使用哪种转换方式。 引用[1]和[2]中提到了写入和读取Paimon表,并输出变更日志(包括+I类型的数据)。因此,我们读取的可能是changelog流。 步骤: 1. 创建流执行环境(StreamExecutionEnvironment)和表环境(StreamTableEnvironment)。 2. 注册Paimon表(或者通过SQL CREATE TABLE语句创建)。 3. 执行SQL查询(流式查询)。 4. 将查询结果的Table转换为DataStream。 转换方法: - 如果查询结果是append-only流(只包含插入操作),则使用`toDataStream`。 - 如果查询结果是changelog流(包含插入、更新、删除等操作),则使用`toChangelogStream`(Flink 1.14+)或者使用`toRetractStream`(旧版,返回Tuple2<Boolean, Row>,其中Boolean表示是新增还是撤回)。 但是,在Flink 1.14及以上版本,推荐使用`TableEnvironment#toChangelogStream`方法将表转换为DataStream,它能够处理各种变更消息。 由于我们读取的是Paimon表,并且配置了流式读取(可能会产生更新和删除),所以应该使用`toChangelogStream`。 示例代码: 假设我们已经有一个StreamTableEnvironment实例`tableEnv`,并且已经创建了Paimon表,然后执行了一个SQL查询。 例如,我们有一个SQL查询: ```sql SELECT user_id, COUNT(*) as cnt FROM my_paimon_table GROUP BY user_id ``` 这个查询会产生更新操作(因为每个新的数据到来可能会改变某个user_id的计数),因此它是一个changelog流。 转换代码: ```java // 执行SQL查询 Table resultTable = tableEnv.sqlQuery("SELECT user_id, COUNT(*) as cnt FROM my_paimon_table GROUP BY user_id"); // 将Table转换为DataStream<Row> DataStream<Row> resultStream = tableEnv.toChangelogStream(resultTable); // 或者,如果我们想得到类型化的DataStream,可以定义Row的类型信息,但通常使用Row即可。 // 也可以使用toDataStream,但仅当表是append-only时,否则会报错。 // 然后可以对resultStream进行后续操作。 ``` 注意:在Flink SQL中,如果表是动态表(即会更新),那么转换为DataStream时,必须使用toChangelogStream。 另外,如果表是仅插入的(例如,没有GROUP BY,只是简单的SELECT),那么可以使用toDataStream。 根据引用[3]中控制台输出的结果,我们看到有`op`列(表示操作类型,如+I),这说明读取的是changelog流。因此,我们应该使用`toChangelogStream`。 但是,在Flink 1.14+中,`toChangelogStream`方法会将表转换为一个DataStream,其中每条记录都代表一个变更事件(包括INSERT、UPDATE_BEFORE、UPDATE_AFTER、DELETE)。在DataStream中,这些事件以Row对象的形式表示,并且Row的第一列通常是一个操作标志(在Flink内部使用,不会直接显示为Row的一个字段,而是通过Row的RowKind来表示)。当我们打印时,可以看到类似+I、-U、+U、-D等前缀。 因此,在代码中,我们可以这样处理: ```java DataStream<Row> stream = tableEnv.toChangelogStream(resultTable); // 打印结果(会显示变更类型) stream.print(); ``` 这样,我们就可以将Flink SQL查询Paimon表的结果转换为DataStream,并进行后续处理。 总结步骤: 1. 设置Flink流执行环境。 2. 创建TableEnvironment。 3. 注册或创建Paimon表(通过SQL DDL)。 4. 执行SQL查询,得到Table对象。 5. 将Table对象转换为DataStream(根据是否是更新流选择toChangelogStream)。 6. 执行DataStream程序(如sink操作)。 注意:在流式读取Paimon时,确保在表属性中配置了`scan.mode='streaming'`,以便持续读取新数据。 示例代码(Java)完整片段: ```java import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; import org.apache.flink.table.api.bridge.java.StreamTableEnvironment; import org.apache.flink.table.api.Table; import org.apache.flink.types.Row; import org.apache.flink.streaming.api.datastream.DataStream; public class PaimonToDataStream { public static void main(String[] args) throws Exception { StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env); // 创建Paimon表(如果已经存在,可以跳过创建,直接使用) String createTableSql = "CREATE TABLE my_paimon_table (\n" + " user_id BIGINT,\n" + " behavior STRING,\n" + " event_time TIMESTAMP(3),\n" + " WATERMARK FOR event_time AS event_time - INTERVAL '5' SECOND\n" + ") WITH (\n" + " 'connector' = 'paimon',\n" + " 'path' = 'file:///path/to/paimon',\n" + " 'changelog-producer' = 'input',\n" + " 'scan.mode' = 'streaming'\n" + ")"; tableEnv.executeSql(createTableSql); // 执行查询 Table resultTable = tableEnv.sqlQuery("SELECT user_id, COUNT(*) as cnt FROM my_paimon_table GROUP BY user_id"); // 转换为DataStream DataStream<Row> resultStream = tableEnv.toChangelogStream(resultTable); // 输出到控制台 resultStream.print(); env.execute("Paimon SQL to DataStream"); } } ``` 注意:在实际使用中,请确保Paimon表的路径和配置正确。 另外,如果不想使用Row类型,也可以将Table转换为特定类型的DataStream(使用`toDataStream(Class)`或`toDataStream(DataType)`),但前提是表是append-only的。对于changelog流,只能使用`toChangelogStream`,并且返回的是DataStream<Row>。 在Scala中,也可以使用类似的API。 后,根据引用[4],Paimon作为流式数据湖,Flink集成良好,因此这种转换是可行的。 引用: [^1]: 在示例中,我们写入了一条`+I`类型的数据,然后读取,说明读取的是变更日志流。 [^2]: 同样,写入`+I`然后读取,输出结果。 [^3]: 输出结果中显示了`op`列(操作类型)和具体数据。 [^4]: Paimon是一个流式数据湖项目,Flink集成。 因此,我们使用`toChangelogStream`将表转换为DataStream是合适的。 相关问题: 1. 在将Flink SQL结果转换为DataStream时,如何处理类型信息? 2. 如何将Paimon表的变更日志流转换为特定类型的DataStream(如POJO)? 3. 在流式转换中,如何保证状态管理和容错?</think>### Flink SQL 流读取 Paimon 表后转换为 DataStream 的步骤 在 Flink SQL 流式读取 Paimon 表后,可通过以下步骤将结果转换为 DataStream: #### 核心转换流程 ```mermaid graph LR A[Flink SQL 查询] --> B(Table API 结果) B --> C{转换方法} C -->|Append-only 流| D[toDataStream] C -->|Changelog 流| E[toChangelogStream] D --> F[DataStream<Row>] E --> F ``` #### 详细步骤(Java 示例) 1. **创建 TableEnvironment 并定义 Paimon 表** ```java StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env); // 定义 Paimon 表(带流式读取配置) tableEnv.executeSql( "CREATE TABLE paimon_table (\n" + " user_id BIGINT,\n" + " behavior STRING,\n" + " event_time TIMESTAMP(3)\n" + ") WITH (\n" + " 'connector' = 'paimon',\n" + " 'path' = 'file:///path/to/paimon',\n" + " 'changelog-producer' = 'input',\n" + " 'scan.mode' = 'streaming'\n" + // 关键流式配置[^1][^2] ")" ); ``` 2. **执行 SQL 查询获取 Table 对象** ```java Table resultTable = tableEnv.sqlQuery( "SELECT user_id, COUNT(*) AS cnt " + "FROM paimon_table " + "GROUP BY user_id" ); ``` 3. **根据查询类型选择转换方法** - **场景 1:Append-only 流(仅插入)** ```java // 适用于简单过滤查询 DataStream<Row> dataStream = tableEnv.toDataStream(resultTable); ``` - **场景 2:Changelog 流(含更新/删除)** ```java // 适用于聚合查询(如引用[3]的GROUP BY结果) DataStream<Row> dataStream = tableEnv.toChangelogStream(resultTable); ``` 4. **处理 DataStream 结果** ```java dataStream.process(new ProcessFunction<Row, Void>() { @Override public void processElement(Row row, Context ctx, Collector<Void> out) { // 识别操作类型(INSERT/UPDATE/DELETE) RowKind kind = row.getKind(); long userId = row.getFieldAs("user_id"); long count = row.getFieldAs("cnt"); System.out.println(kind.shortString() + " | " + userId + " : " + count); } }); env.execute(); ``` #### 关键配置说明 1. **流式读取必需参数** ```sql 'scan.mode' = 'streaming', -- 启用流式扫描[^1] 'changelog-producer' = 'input' -- 捕获实时变更[^2] ``` 2. **数据类型映射** | SQL 类型 | DataStream 类型 | 处理方式 | |------------------|----------------------|----------------------| | `BIGINT` | `Long` | `row.getFieldAs()` | | `TIMESTAMP(3)` | `java.time.Instant` | 需显式转换 | | `ROW` | `Row` | 嵌套字段需逐层解析 | 3. **操作类型识别** ```java // 输出示例(引用[3]格式): // +I | 123 : 5 // INSERT // -U | 123 : 5 // UPDATE_BEFORE // +U | 123 : 6 // UPDATE_AFTER row.getKind().shortString(); ``` #### 注意事项 1. **水位线传递** 需在 Table 定义中声明 `WATERMARK`,否则 DataStream 无法获取事件时间: ```sql WATERMARK FOR event_time AS event_time - INTERVAL '5' SECOND ``` 2. **容错机制** 启用 Checkpoint 保证状态一致性: ```java env.enableCheckpointing(5000); // 5秒间隔 ``` 3. **性能优化** - 使用 `env.setParallelism()` 调整并行度 - 在 Paimon 表配置中启用压缩: ```sql 'compaction.min.file-num' = '3', 'compaction.max.file-num' = '10' ``` #### 完整执行流程 1. 写入数据到 Paimon(如引用[1][2]示例) 2. 流式 SQL 查询新数据 3. 通过 `toChangelogStream()` 转换 4. 在 DataStream 中处理变更事件 5. 输出结果(如引用[3]的控制台格式) > **提示**:当查询包含 `GROUP BY` 等聚合操作时,必须使用 `toChangelogStream()` 才能正确处理更新消息[^3]。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值