Flink_08_SQL(个人总结)

    声明: 1. 本文为我的个人复习总结, 并那种从零基础开始普及知识 内容详细全面, 言辞官方的文章
              2. 由于是个人总结, 所以用最精简的话语来写文章
              3. 若有错误不当之处, 请指出

FlinkSQL & TableAPI:

创建表环境, 创建表, 表数据和流数据的互转 要用到TableAPI

对于写SQL部分:

​ FlinkSQL是直接写SQL, 查询用的直接就是SQL的select关键字,

​ 而TableAPI的查询用的是select( )API;

API是流批一体

Table:

表是由 CataLog+数据库+表名 组成的, CataLog和数据库有默认值

CataLogSchema > DataBaseSchema > Table

CataLogSchema 里存储元数据信息, 如数据库, 表, 视图的信息

创建表环境:

// 直接创建, 基于流处理
StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env);

// 带上EnvironmentSettings的方式
// 基于流处理
EnvironmentSettings bsSettings = EnvironmentSettings.newInstance( )
    .useBlinkPlanner( )
    .inStreamingMode( )
    .build( );
StreamTableEnvironment bsTableEnv = StreamTableEnvironment.create(env, bsSettings);

// 基于批处理
EnvironmentSettings bbSettings = EnvironmentSettings.newInstance( )
    .useBlinkPlanner( )
    .inBatchMode( )
    .build( );
TableEnvironment bbTableEnv = TableEnvironment.create(bbSettings);

输入:

1. 把DataStream转为Table(常用):

这种表的数据是不断变化的, 是动态表

Table sensorTable = tableEnv.fromDataStream(dataStream, "id, timestamp.rowtime as ts, temperature");

2. 根据外部系统创建Table:

需要自己指明文件格式(用来分割字段), 字段名称

通过定义TableSchema:

CSV:

tableEnv.connect(new FileSystem( ).path("sensor.txt")) 
    .withFormat(new Csv( ))  
    .withSchema(new Schema( )
    .field("id", DataTypes.STRING( ))
    .field("timestamp", DataTypes.BIGINT( ))
    .field("temperature", DataTypes.DOUBLE( ))
    )  
    .createTemporaryTable("inputTable"); 

Kafka:

tableEnv.connect(
    new Kafka( )
    .version("0.11") 
    .topic("sensor")
    .property("zookeeper.connect", "localhost:2181")
    .property("bootstrap.servers", "localhost:9092"))
    .withFormat(new Csv( ))
    .withSchema(new Schema( )
    .field("id", DataTypes.STRING( ))
    .field("timestamp", DataTypes.BIGINT( ))
    .field("temperature", DataTypes.DOUBLE( ))
    )
    .createTemporaryTable("kafkaInputTable");

通过写SQL的DDL语句:

String sinkDDL = "create table dataTable (" +
 " id varchar(20) not null, " +
 " ts bigint, " +
 " temperature double"
  ) with (" +
 " 'connector.type' = 'filesystem', " +
 " 'connector.path' = '/sensor.txt', " +
 " 'format.type' = 'csv')";
tableEnv.sqlUpdate(sinkDDL);

还支持: ElasticSearch、MySQL、HBase、Hive

指定时间字段 & 时间语义:

  1. DataStream 转化成 Table 时指定

    // 事件时间, 在DataStream里指定watermark延迟时间
     .assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractor<SensorReading>(Time.seconds(1)) {
    	 @Override
    	 public long extractTimestamp(SensorReading element) {
    		 return element.getTimestamp( ) * 1000L;
             }
     });
    Table sensorTable = tableEnv.fromDataStream(dataStream, "id, temperature, timestamp.rowtime");
    
    
    //处理时间, 新增一个字段作为时间字段
    Table sensorTable = tableEnv.fromDataStream(dataStream, "id, temperature, timestamp, pt.proctime");
    
  2. 定义 Table Schema 表结构时指定

    // 事件时间
    tableEnv.connect(
     new FileSystem( ).path("sensor.txt"))
     .withFormat(new Csv( ))
     .withSchema(new Schema( )
     .field("id", DataTypes.STRING( ))
     .field("timestamp", DataTypes.BIGINT( ))
     .rowtime(
     new Rowtime( )
     .timestampsFromField("timestamp")  
     .watermarksPeriodicBounded(1000) 
     )
     .field("temperature", DataTypes.DOUBLE( ))
     )  
     .createTemporaryTable("inputTable");  
    
    
    // 处理时间
    tableEnv.connect(
     new FileSystem( ).path("..\\sensor.txt"))
     .withFormat(new Csv( ))
     .withSchema(new Schema( )
     .field("id", DataTypes.STRING( ))
     .field("timestamp", DataTypes.BIGINT( ))
     .field("temperature", DataTypes.DOUBLE( ))
     .field("pt", DataTypes.TIMESTAMP(3))
     .proctime( ) 
     )  
     .createTemporaryTable("inputTable");  
    
  3. 创建表时写SQL的DDL语句中指定

    // 事件时间
    String sinkDDL = "create table dataTable (" +
     " id varchar(20) not null, " +
     " ts bigint, " +
     " temperature double, " +
     " rt AS TO_TIMESTAMP( FROM_UNIXTIME(ts) ), " +
     " watermark for rt as rt - interval '1' second" +
     ") with (" +
     " 'connector.type' = 'filesystem', " +
     " 'connector.path' = '/sensor.txt', " +
     " 'format.type' = 'csv')";
    tableEnv.sqlUpdate(sinkDDL);
    
    
    // 处理时间
    String sinkDDL = "create table dataTable (" +
     " id varchar(20) not null, " +
     " ts bigint, " +
     " temperature double, " +
     " pt AS PROCTIME( ) " +
     ") with (" +
     " 'connector.type' = 'filesystem', " +
     " 'connector.path' = '/sensor.txt', " +
     " 'format.type' = 'csv')";
    tableEnv.sqlUpdate(sinkDDL);
    

输出:

1. 把Table转为DataStream:

没聚合操作 || 聚合 + window, 一般用追加模式 (在窗口关闭时才进行计算, 就也为追加模式了)

聚合+非window, 一般用撤回模式(有更新操作)

  1. 追加模式

    DataStream<Row> resultStream = tableEnv.toAppendStream(resultTable,Row.class);
    
  2. 撤回模式

    DataStream<Tuple2<Boolean, Row>> aggResultStream = tableEnv.toRetractStream(aggResultTable, Row.class);aggResultStream.print("aggResult");
    

2. 输出到外部系统:

文件:

// 构建TableSink表信息tableEnv.connect(new FileSystem( ).path("…\\resources\\out.txt"))    		 .withFormat(new Csv( ))    	        .withSchema(new Schema( )              .field("id", DataTypes.STRING( ))              .field("temp", DataTypes.DOUBLE( ))          	)   		 .createTemporaryTable("outputTable"); // 输出到TableSinkresultSqlTable.insertInto("outputTable");

更新模式:

  1. 追加模式(Append Mode)

    只有insert

  2. 撤回模式(Retract Mode)

    有insert, delete

  3. 更新插入模式(Upsert Mode)

    有upsert

    输出到外部文件系统时才能用(控制台打印时没法撤回的)

Window:

  1. 滚动窗口

    TUMBLE(time_attr, interval)

    TUMBLE_PROCTIME(time_attr, interval)

    TUMBLE_ROWTIME(time_attr, interval)

  2. 滑动窗口

    HOP(time_attr, interval, interval)

    HOP_PROCTIME(time_attr, interval, interval)

    HOP_ROWTIME(time_attr, interval, interval)

    这里参数是与DataStream反着来的, 第一个interval是窗口滑动步长, 第二个interval是窗口大小

  3. 会话窗口

    SESSION(time_attr, interval)

    SESSION_PROCTIME(time_attr, interval)

    SESSION_ROWTIME(time_attr, interval)

其他相关函数:

TUMBLE_START(time_attr, interval)
HOP_START(time_attr, interval, interval)
SESSION_START(time_attr, interval)

HOP_ROWTIME(time_attr, interval, interval)
SESSION_ROWTIME(time_attr, interval)

函数:

系统函数:

power(x,y)

upper(“hello”)

char_length(“hello”)

date ‘2020-06-14’

timestamp ‘2020-06-14’

to_timestamp (from_unixtime(ts, ‘格式’)) 格式默认为’YYYY-MM-DD hh:mm:ss’

current_time

开创函数over:

partitionBy 可选

orderBy 必选, 且指定字段为 时间语义的字段(是处理时间时, 额外生成了一个时间字段)

preceding 可选

自定义UDF:

  1. 继承ScalarFunction
  2. 编写eval方法

自定义UDTF:

  1. 继承TableFunction<OUT>
  2. 编写eval方法

SQL写法, 字段可以被单引号引住

侧写:

-- 相当于隐式地 侧写split(id) as idselect id, word from movie, lateral table(split(id))

自定义UDAF:

  1. 继承AggregateFunction<OUT,STATE>

    STATE是中间数据类型

  2. 重写createAccumulator方法

  3. 重写getValue方法

  4. 编写accumulate方法

自定义UDTAF

这个只能用TableAPI的方式, 不支持FlinkSQL的方式

常用作求topN

其实就是先分组, 后聚合侧写(这个聚合侧写是输出每个小组里的topN)

  1. 继承TableAggregateFunction<OUT,STATE>
  2. 重写createAccumulator方法
  3. 编写emitValue方法
  4. 编写accumulate方法

Join:

join时肯定要用到状态, 可以指定状态的最大时间

// 0代表状态永不清空tableEnv.getConfig( ).setIdleStateRetention(Duration.ofSeconds(10))

这个最大时间是指 距离最近一次使用超过多长时间后才清空, 类似于Session的概念

底层实现起来就是定时器:

定时器里去执行清空状态的任务, 每当有数据发生join时: 便把当前定时器删掉, 然后重新注册定时器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值