Flink dataStream和Table转换中的类型映射举例

上代码:


    @Test
    public void testFlinkTypeConversion() throws Exception {
        StreamExecutionEnvironment senv = StreamExecutionEnvironment.getExecutionEnvironment();
        StreamTableEnvironment tenv = StreamTableEnvironment.create(senv);
        Row r1 = new Row(RowKind.INSERT, 5);
        r1.setField(0, "xiao");
        // r1.setField(1, LocalDate.now());
        r1.setField(1, new java.sql.Date(2000));
        r1.setField(2, 100);
        r1.setField(3, new BigDecimal("100.123"));
        r1.setField(4, new Timestamp(1691733766000L));

        // row中的数据类型必须和return类型完全对应。
        DataStream<Row> dataStream = senv.fromElements(r1)
                .returns(Types.ROW_NAMED(new String[]{"name", "date", "length", "money", "ts"}, Types.STRING, Types.SQL_DATE, Types.INT, Types.BIG_DEC, Types.SQL_TIMESTAMP));
        System.out.println(dataStream.getTransformation().getOutputType());
        // Row(name: String, date: Date, length: Integer, money: BigDecimal, ts: Timestamp)

        Schema resolvedSchema = Schema.newBuilder()
                .column("name", DataTypes.STRING())
                .column("date", DataTypes.DATE().bridgedTo(java.sql.Date.class)) // default conversionClass:java.time.LocalDate
                .column("length", DataTypes.INT())
                .column("money", DataTypes.DECIMAL(10, 3))
                .column("ts", DataTypes.TIMESTAMP(3).bridgedTo(Timestamp.class))  //  default conversionClass:java.time.LocalDateTime
                .build();

        Schema unresolvedSchema = Schema.newBuilder()
                .column("name", "STRING")
                .column("date", "DATE")
                .column("length", "INT")
                .column("money", "DECIMAL(10,3)")
                .column("ts", "TIMESTAMP(3)")
                .build();
        Table tbl;
        // only insert-only DataStream as a Table,即 不是RowKind.INSERT都不支持!
        // tbl = tenv.fromDataStream(dataStream,resolvedSchema);

        // (1)是否提供schema都可以,但提供了schema则必须和dataStream的数据类型完全一致
        //    如schema中DataType的conversionClass(getConversionClass获取的)必须和dataStream中的数据类型一致
        //    如果不一致必须使用`DataTypes.类型.bridgeTo(ConversionClass.class)`进行转换
        //    可不提供schema会自动从dataStream中推断但都是按照最大原则推断的
        //    比如 提供schema:`money` DECIMAL(10, 3) --- > 不提供schema:`money` DECIMAL(38, 18),

        // (2)不使用DataTypes生成类型,而是用String提供类型
        //    如果使用 unresolvedSchema 则需要注意:dataStream内的数据类型必须是
        //    org.apache.flink.table.types.logical.LogicalType.getDefaultConversion的类型才可以
        //    否则报错:Caused by: java.lang.ClassCastException

        // 综合最推荐使用 resolvedSchema形式,次之不指定schema。不推荐使用unresolvedSchema形式。
        tbl = tenv.fromChangelogStream(dataStream, resolvedSchema);
        ResolvedSchema rs = tbl.getResolvedSchema();
        tbl.printSchema();
/*(
  `name` STRING,
  `date` DATE,
  `length` INT,
  `money` DECIMAL(10, 3),
  `ts` TIMESTAMP(3)
)*/

        Schema outputSchema = Schema.newBuilder()
                .column("name", DataTypes.STRING())
                .column("date", DataTypes.DATE().bridgedTo(Integer.class))

                .column("length", DataTypes.BIGINT())
                .column("money", DataTypes.DECIMAL(10, 3).bridgedTo(DecimalData.class))
                .column("ts", DataTypes.TIMESTAMP(3).bridgedTo(TimestampData.class))
                .build();

        // outputSchema的作用是将Table中的类型转换成指定的物理类型。
        // (1) logicalType不修改
        // 使用`bridgeTo(class)`进行指定。所制定类型必须在DataType所持有的LogicalType.supportsOutputConversion中。
        //
        // (2) logicalType修改
        // 如果tbl 是bigint toChangelogStream 参数Schema是int则会报错:Cause: Incompatible types for sink column 'length'
        // 如果tbl 是int toChangelogStream 参数Schema是bigint则可成功。
        // 也就是只支持扩大值范围的类型的转换。并不是转换。和java的 (int)1000L ,此转换会直接报错。
        DataStream<Row> convertedDs = tenv.toChangelogStream(tbl, outputSchema);
        convertedDs.map(new MapFunction<Row, Row>() {
            @Override
            public Row map(Row value) throws Exception {
                Row output = new Row(value.getKind(), value.getArity());
                for (int i = 0; i < value.getArity(); i++) {
                    Object val = value.getField(i);
                    output.setField(i, String.format("clazz:%s, value:%s", val.getClass().getSimpleName(), val.toString()));
                }
                return output;
            }
        }).print();
// 可以看到都根据brideTo指定的类型进行了输出转换!
// +I[clazz:String, value:xiao, clazz:Integer, value:0, clazz:Long, value:100, clazz:DecimalData, value:100.123, clazz:TimestampData, value:2023-08-11T14:02:46]
        senv.execute();
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值