Table API 和 Flink SQL

Flink快速入门-11.Flink 中 Table API 和 SQL 在 Spark 中,最基础的编程模型是 RDD 编程。但是并不是所有的程序员都能够用 RDD 很好地处理数据,所以 Spark 社区在 RDD 的基础上增加了关系型编程接口 Spark DataFrame 和 Spark SQL。Spark DataFrame 和 Spark SQL 的出现,大大降低了 Spark 的使用门槛,使那些并不擅长 Scala 以及只会 SQL 的程序员和数据分析师也能利用 Spark 的分析能力进行大数据分析。 阅读详情
Table API 和 Flink SQL
Table API 和 Flink SQL 是什么
• Flink 对批处理和流处理,提供了统一的上层 API
• Table API 是一套内嵌在 Java 和 Scala 语言中的查询API,它允许以非常直观
的方式组合来自一些关系运算符的查询
• Flink 的 SQL 支持基于实现了 SQL 标准的 Apache Calcite基本程序结构
• Table API 和 SQL 的程序结构,与流式处理的程序结构十分类似
val tableEnv = ...
// 创建表的执行环境
// 创建一张表,用于读取数据
tableEnv.connect(...).createTemporaryTable("inputTable")
// 注册一张表,用于把计算结果输出
tableEnv.connect(...).createTemporaryTable("outputTable")
// 通过 Table API 查询算子,得到一张结果表
val result = tableEnv.from("inputTable").select(...)
// 通过 SQL查询语句,得到一张结果表
val sqlResult = tableEnv.sqlQuery("SELECT ... FROM inputTable ...")
// 将结果表写入输出表中
result.insertInto("outputTable")创建 TableEnvironment
• 创建表的执行环境,需要将 flink 流处理的执行环境传入
val tableEnv = StreamTableEnvironment.create(env)
• TableEnvironment 是 flink 中集成 Table API 和 SQL 的核心概念,所有对表
的操作都基于 TableEnvironment
– 注册 Catalog
– 在 Catalog 中注册表
– 执行 SQL 查询
– 注册用户自定义函数(UDF)配置 TableEnvironment
• 配置老版本 planner 的流式查询
val settings = EnvironmentSettings.newInstance()
.useOldPlanner()
.inStreamingMode()
.build()
val tableEnv = StreamTableEnvironment.create(env, settings)
• 配置老版本 planner 的批式查询
val batchEnv = ExecutionEnvironment.getExecutionEnvironment
val batchTableEnv = BatchTableEnvironment.create(batchEnv)配置 TableEnvironment
• 配置 blink planner 的流式查询
val bsSettings = EnvironmentSettings.newInstance()
.useBlinkPlanner()
.inStreamingMode()
.build()
val bsTableEnv = StreamTableEnvironment.create(env, bsSettings)
• 配置 blink planner 的批式查询
val bbSettings = EnvironmentSettings.newInstance()
.useBlinkPlanner()
.inBatchMode()
.build()
val bbTableEnv = TableEnvironment.create(bbSettings)表(Table)
• TableEnvironment 可以注册目录 Catalog,并可以基于 Catalog 注册表
• 表(Table)是由一个“标识符”(identifier)来指定的,由3部分组成:
Catalog名、数据库(database)名和对象名
• 表可以是常规的,也可以是虚拟的(视图,View)
• 常规表(Table)一般可以用来描述外部数据,比如文件、数据库表或消息队
列的数据,也可以直接从 DataStream转换而来
• 视图(View)可以从现有的表中创建,通常是 table API 或者 SQL 查询的一
个结果集创建表
• TableEnvironment 可以调用 .connect() 方法,连接外部系统,并调
用 .createTemporaryTable() 方法,在 Catalog 中注册表
tableEnv
.connect(...) // 定义表的数据来源,和外部系统建立连接
.withFormat(...)
// 定义数据格式化方法
.withSchema(...) // 定义表结构
.createTemporaryTable("MyTable") // 创建临时表创建表
• 可以创建 Table 来描述文件数据,它可以从文件中读取,或者将数据写入文件
tableEnv
.connect(
new FileSystem().path(“YOUR_Path/sensor.txt”)
) // 定义到文件系统的连接
.withFormat(new Csv()) // 定义以csv格式进行数据格式化
.withSchema( new Schema()
.field("id", DataTypes.STRING())
.field("timestamp", DataTypes.BIGINT())
.field("temperature", DataTypes.DOUBLE())
) // 定义表结构
.createTemporaryTable("sensorTable") // 创建临时表表的查询 – Table API
• Table API 是集成在 Scala 和 Java 语言内的查询 API
• Table API 基于代表“表”的 Table 类,并提供一整套操作处理的方法 API;这
些方法会返回一个新的 Table 对象,表示对输入表应用转换操作的结果
• 有些关系型转换操作,可以由多个方法调用组成,构成链式调用结构
val sensorTable: Table = tableEnv.from("inputTable")
val resultTable: Table = sensorTable
.select("id, temperature")
.filter("id = 'sensor_1'")表的查询 – SQL
• Flink 的 SQL 集成,基于实现 了SQL 标准的 Apache Calcite
• 在 Flink 中,用常规字符串来定义 SQL 查询语句
• SQL 查询的结果,也是一个新的 Table
val resultSqlTable: Table = tableEnv
.sqlQuery("select id, temperature from sensorTable where id ='sensor_1'")将 DataStream 转换成表
• 对于一个 DataStream,可以直接转换成 Table,进而方便地调用 Table API
做转换操作
val dataStream: DataStream[SensorReading] = ...
val sensorTable: Table = tableEnv.fromDataStream(dataStream)
• 默认转换后的 Table schema 和 DataStream 中的字段定义一一对应,也可以
单独指定出来
val dataStream: DataStream[SensorReading] = ...
val sensorTable = tableEnv.fromDataStream(dataStream,
'id, 'timestamp, 'temperature)数据类型与 Schema 的对应
• DataStream 中的数据类型,与表的 Schema 之间的对应关系,可以有两种:
基于字段名称,或者基于字段位置
• 基于名称(name-based)
val sensorTable = tableEnv.fromDataStream(dataStream,
'timestamp as 'ts, 'id as 'myId, 'temperature)
• 基于位置(position-based)
val sensorTable = tableEnv.fromDataStream(dataStream, 'myId, 'ts)创建临时视图(Temporary View)
• 基于 DataStream 创建临时视图
tableEnv.createTemporaryView("sensorView", dataStream)
tableEnv.createTemporaryView("sensorView",
dataStream, 'id, 'temperature, 'timestamp as 'ts)
• 基于 Table 创建临时视图
tableEnv.createTemporaryView("sensorView", sensorTable)输出表
• 表的输出,是通过将数据写入 TableSink 来实现的
• TableSink 是一个通用接口,可以支持不同的文件格式、存储数据库和消息队列
• 输出表最直接的方法,就是通过 Table.insertInto() 方法将一个 Table 写入注册
过的 TableSink 中
tableEnv.connect(...)
.createTemporaryTable("outputTable")
val resultSqlTable: Table = ...
resultTable.insertInto("outputTable")输出到文件
tableEnv.connect(
new FileSystem().path("output.txt")
) // 定义到文件系统的连接
.withFormat(new Csv())
.withSchema(new Schema()
.field("id", DataTypes.STRING())
.field("temp", DataTypes.Double())
)
.createTemporaryTable("outputTable")
// 创建临时表
resultTable.insertInto("outputTable")
// 输出表更新模式
• 对于流式查询,需要声明如何在表和外部连接器之间执行转换
• 与外部系统交换的消息类型,由更新模式(Update Mode)指定
➢ 追加(Append)模式
– 表只做插入操作,和外部连接器只交换插入(Insert)消息
➢ 撤回(Retract)模式
– 表和外部连接器交换添加(Add)和撤回(Retract)消息
– 插入操作(Insert)编码为 Add 消息;删除(Delete)编码为 Retract 消息;更新(Update)
编码为上一条的 Retract 和下一条的 Add 消息
➢ 更新插入(Upsert)模式
– 更新和插入都被编码为 Upsert 消息;删除编码为 Delete 消息输出到 Kafka
• 可以创建 Table 来描述 kafka 中的数据,作为输入或输出的 TableSink
tableEnv.connect(
new Kafka()
.version("0.11")
.topic("sinkTest")
.property("zookeeper.connect", "localhost:2181")
.property("bootstrap.servers", "localhost:9092")
)
.withFormat( new Csv() )
.withSchema( new Schema()
.field("id", DataTypes.STRING())
.field("temp", DataTypes.DOUBLE())
)
.createTemporaryTable("kafkaOutputTable")
resultTable.insertInto("kafkaOutputTable")输出到 ES
• 可以创建 Table 来描述 ES 中的数据,作为输出的 TableSink
tableEnv.connect(
new Elasticsearch()
.version("6")
.host("localhost", 9200, "http")
.index("sensor")
.documentType("temp")
)
.inUpsertMode()
.withFormat(new Json())
.withSchema( new Schema()
.field("id", DataTypes.STRING())
.field("count", DataTypes.BIGINT())
)
.createTemporaryTable("esOutputTable")
aggResultTable.insertInto("esOutputTable")输出到 MySql
• 可以创建 Table 来描述 MySql 中的数据,作为输入和输出
val sinkDDL: String =
"""
|create table jdbcOutputTable (
|
id varchar(20) not null,
|
cnt bigint not null
|) with (
|
'connector.type' = 'jdbc',
|
'connector.url' = 'jdbc:mysql://localhost:3306/test',
|
'connector.table' = 'sensor_count',
|
'connector.driver' = 'com.mysql.jdbc.Driver',
|
'connector.username' = 'root',
|
'connector.password' = '123456'
|)
""".stripMargin
tableEnv.sqlUpdate(sinkDDL) // 执行 DDL创建表
aggResultSqlTable.insertInto("jdbcOutputTable")将 Table 转换成 DataStream
• 表可以转换为 DataStream 或 DataSet ,这样自定义流处理或批处理程序就
可以继续在 Table API 或 SQL 查询的结果上运行了
• 将表转换为 DataStream 或 DataSet 时,需要指定生成的数据类型,即要将
表的每一行转换成的数据类型
• 表作为流式查询的结果,是动态更新的
• 转换有两种转换模式:追加(Appende)模式和撤回(Retract)模式将 Table 转换成 DataStream
➢ 追加模式(Append Mode)
– 用于表只会被插入(Insert)操作更改的场景
val resultStream: DataStream[Row] = tableEnv.toAppendStream[Row](resultTable)
➢ 撤回模式(Retract Mode)
– 用于任何场景。有些类似于更新模式中 Retract 模式,它只有 Insert 和 Delete 两类操作。
– 得到的数据会增加一个 Boolean 类型的标识位(返回的第一个字段),用它来表示到底是
新增的数据(Insert),还是被删除的数据(Delete)
val aggResultStream: DataStream[(Boolean, (String, Long))] = tableEnv
.toRetractStream[(String, Long)](aggResultTable)查看执行计划
• Table API 提供了一种机制来解释计算表的逻辑和优化查询计划
• 查看执行计划,可以通过 TableEnvironment.explain(table) 方法或
TableEnvironment.explain() 方法完成,返回一个字符串,描述三个计划
➢ 优化的逻辑查询计划
➢ 优化后的逻辑查询计划
➢ 实际执行计划。
val explaination: String = tableEnv.explain(resultTable)
println(explaination)流处理和关系代数的区别
关系代数(表)/SQL
流处理
处理的数据对象
字段元组的有界集合
字段元组的无限序列
查询(Query)
对数据的访问
可以访问到完整的数据输入
无法访问所有数据,
必须持续“等待”流式输入
查询终止条件
生成固定大小的结果集后终止
永不停止,根据持续收到的
数据不断更新查询结果动态表(Dynamic Tables)
• 动态表是 Flink 对流数据的 Table API 和 SQL 支持的核心概念
• 与表示批处理数据的静态表不同,动态表是随时间变化的
➢ 持续查询(Continuous Query)
• 动态表可以像静态的批处理表一样进行查询,查询一个动态表会产生持续查
询(Continuous Query)
• 连续查询永远不会终止,并会生成另一个动态表
• 查询会不断更新其动态结果表,以反映其动态输入表上的更改动态表和持续查询
➢ 流式表查询的处理过程:
1. 流被转换为动态表
2. 对动态表计算连续查询,生成新的动态表
3. 生成的动态表被转换回流将流转换成动态表
• 为了处理带有关系查询的流,必须先将其转换为表
• 从概念上讲,流的每个数据记录,都被解释为对结果表的插入
(Insert)修改操作持续查询
• 持续查询会在动态表上做计算处理,并作为结果生成新的动态表将动态表转换成 DataStream
•
与常规的数据库表一样,动态表可以通过插入(Insert)、更新(Update)和删
除(Delete)更改,进行持续的修改
•
将动态表转换为流或将其写入外部系统时,需要对这些更改进行编码
➢ 仅追加(Append-only)流
– 仅通过插入(Insert)更改来修改的动态表,可以直接转换为仅追加流
➢ 撤回(Retract)流
– 撤回流是包含两类消息的流:添加(Add)消息和撤回(Retract)消息
➢ Upsert(更新插入)流
– Upsert 流也包含两种类型的消息:Upsert 消息和删除(Delete)消息。将动态表转换成 DataStream
Dynamic Table
Retract Stream
Dynamic Table
Upsert Stream时间特性(Time Attributes)
• 基于时间的操作(比如 Table API 和 SQL 中窗口操作),需要定义相关的时
间语义和时间数据来源的信息
• Table 可以提供一个逻辑上的时间字段,用于在表处理程序中,指示时间和访
问相应的时间戳
• 时间属性,可以是每个表schema的一部分。一旦定义了时间属性,它就可以
作为一个字段引用,并且可以在基于时间的操作中使用
• 时间属性的行为类似于常规时间戳,可以访问,并且进行计算定义处理时间(Processing Time)
• 处理时间语义下,允许表处理程序根据机器的本地时间生成结果。它是时间
的最简单概念。它既不需要提取时间戳,也不需要生成 watermark
➢ 由 DataStream 转换成表时指定
• 在定义Schema期间,可以使用.proctime,指定字段名定义处理时间字段
• 这个proctime属性只能通过附加逻辑字段,来扩展物理schema。因此,只能
在schema定义的末尾定义它
val sensorTable = tableEnv.fromDataStream(dataStream,
'id, 'temperature, 'timestamp, 'pt.proctime)定义处理时间(Processing Time)
➢ 定义 Table Schema 时指定
.withSchema(new Schema()
.field("id", DataTypes.STRING())
.field("timestamp", DataTypes.BIGINT())
.field("temperature", DataTypes.DOUBLE())
.field("pt", DataTypes.TIMESTAMP(3))
.proctime()
)定义处理时间(Processing Time)
➢ 在创建表的 DDL 中定义
val sinkDDL: String =
"""
|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'
|)
""".stripMargin
tableEnv.sqlUpdate(sinkDDL)定义事件时间(Event Time)
• 事件时间语义,允许表处理程序根据每个记录中包含的时间生成结果。这样
即使在有乱序事件或者延迟事件时,也可以获得正确的结果。
• 为了处理无序事件,并区分流中的准时和迟到事件;Flink 需要从事件数据中,
提取时间戳,并用来推进事件时间的进展
• 定义事件时间,同样有三种方法:
➢ 由 DataStream 转换成表时指定
➢ 定义 Table Schema 时指定
➢ 在创建表的 DDL 中定义定义事件时间(Event Time)
➢ 由 DataStream 转换成表时指定
• 在 DataStream 转换成 Table,使用 .rowtime 可以定义事件时间属性
// 将 DataStream转换为 Table,并指定时间字段
val sensorTable = tableEnv.fromDataStream(dataStream,
'id, 'timestamp.rowtime, 'temperature)
// 或者,直接追加时间字段
val sensorTable = tableEnv.fromDataStream(dataStream,
'id, 'temperature, 'timestamp, 'rt.rowtime)定义事件时间(Event Time)
• 定义 Table Schema 时指定
.withSchema(new Schema()
.field("id", DataTypes.STRING())
.field("timestamp", DataTypes.BIGINT())
.rowtime(
new Rowtime()
.timestampsFromField("timestamp") // 从字段中提取时间戳
.watermarksPeriodicBounded(1000) // watermark延迟1秒
)
.field("temperature", DataTypes.DOUBLE())
)定义事件时间(Event Time)
• 在创建表的 DDL 中定义
val sinkDDL: String =
"""
|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'
|)
""".stripMargin
tableEnv.sqlUpdate(sinkDDL)窗口
• 时间语义,要配合窗口操作才能发挥作用
• 在 Table API 和 SQL 中,主要有两种窗口
➢ Group Windows(分组窗口)
– 根据时间或行计数间隔,将行聚合到有限的组(Group)中,并对每个组的数据执
行一次聚合函数
➢ Over Windows
– 针对每个输入行,计算相邻行范围内的聚合Group Windows
• Group Windows 是使用 window(w:GroupWindow)子句定义的,并且必
须由as子句指定一个别名。
• 为了按窗口对表进行分组,窗口的别名必须在 group by 子句中,像常规的
分组字段一样引用
val table = input
.window([w: GroupWindow] as 'w) // 定义窗口,别名为 w
.groupBy('w, 'a)
// 按照字段 a和窗口 w分组
.select('a, 'b.sum) // 聚合
• Table API 提供了一组具有特定语义的预定义 Window 类,这些类会被转换
为底层 DataStream 或 DataSet 的窗口操作滚动窗口(Tumbling windows)
• 滚动窗口要用 Tumble 类来定义
// Tumbling Event-time Window
.window(Tumble over 10.minutes on 'rowtime as 'w)
// Tumbling Processing-time Window
.window(Tumble over 10.minutes on 'proctime as 'w)
// Tumbling Row-count Window
.window(Tumble over 10.rows on 'proctime as 'w)滑动窗口(Sliding windows)
• 滑动窗口要用 Slide 类来定义
// Sliding Event-time Window
.window(Slide over 10.minutes every 5.minutes on 'rowtime as 'w)
// Sliding Processing-time window
.window(Slide over 10.minutes every 5.minutes on 'proctime as 'w)
// Sliding Row-count window
.window(Slide over 10.rows every 5.rows on 'proctime as 'w)会话窗口(Session windows)
• 会话窗口要用 Session 类来定义
// Session Event-time Window
.window(Session withGap 10.minutes on 'rowtime as 'w)
// Session Processing-time Window
.window(Session withGap 10.minutes on 'proctime as 'w)Over Windows
• Over window 聚合是标准 SQL 中已有的(over 子句),可以在查询的
SELECT 子句中定义
• Over window 聚合,会针对每个输入行,计算相邻行范围内的聚合
• Over windows 使用 window(w:overwindows*)子句定义,并在 select()
方法中通过别名来引用
val table = input
.window([w: OverWindow] as 'w)
.select('a, 'b.sum over 'w, 'c.min over 'w)
• Table API 提供了 Over 类,来配置 Over 窗口的属性无界 Over Windows
• 可以在事件时间或处理时间,以及指定为时间间隔、或行计数的范围内,定
义 Over windows
• 无界的 over window 是使用常量指定的
// 无界的事件时间 over window
.window(Over partitionBy 'a orderBy 'rowtime preceding UNBOUNDED_RANGE as 'w)
//无界的处理时间 over window
.window(Over partitionBy 'a orderBy 'proctime preceding UNBOUNDED_RANGE as 'w)
// 无界的事件时间 Row-count over window
.window(Over partitionBy 'a orderBy 'rowtime preceding UNBOUNDED_ROW as 'w)
//无界的处理时间 Row-count over window
.window(Over partitionBy 'a orderBy 'proctime preceding UNBOUNDED_ROW as 'w)有界 Over Windows
• 有界的 over window 是用间隔的大小指定的
// 有界的事件时间 over window
.window(Over partitionBy 'a orderBy 'rowtime preceding 1.minutes as 'w)
// 有界的处理时间 over window
.window(Over partitionBy 'a orderBy 'proctime preceding 1.minutes as 'w)
// 有界的事件时间 Row-count over window
.window(Over partitionBy 'a orderBy 'rowtime preceding 10.rows as 'w)
// 有界的处理时间 Row-count over window
.window(Over partitionBy 'a orderBy 'proctime preceding 10.rows as 'w)SQL 中的 Group Windows
• Group Windows 定义在 SQL 查询的 Group By 子句中
➢ TUMBLE(time_attr, interval)
•
定义一个滚动窗口,第一个参数是时间字段,第二个参数是窗口长度
➢ HOP(time_attr, interval, interval)
•
定义一个滑动窗口,第一个参数是时间字段,第二个参数是窗口滑动步长,第三个是
窗口长度
➢ SESSION(time_attr, interval)
•
定义一个会话窗口,第一个参数是时间字段,第二个参数是窗口间隔SQL 中的 Over Windows
• 用 Over 做窗口聚合时,所有聚合必须在同一窗口上定义,也就是说必须是
相同的分区、排序和范围
• 目前仅支持在当前行范围之前的窗口
• ORDER BY 必须在单一的时间属性上指定
SELECT COUNT(amount) OVER (
PARTITION BY user
ORDER BY proctime
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW)
FROM Orders函数(Functions)
• Flink Table API 和 SQL 为用户提供了一组用于数据转换的内置函数
• SQL 中支持的很多函数,Table API 和 SQL 都已经做了实现
➢ 比较函数
• SQL:
- value1 = value2
- value1 > value2
• Table API:
- ANY1 === ANY2
- ANY1 > ANY2
➢ 逻辑函数
• SQL:
- boolean1 OR boolean2
- boolean IS FALSE
- NOT boolean
• Table API:
- BOOLEAN1 || BOOLEAN2
- BOOLEAN.isFalse
- !BOOLEAN
➢ 算数函数
• SQL:
- numeric1 + numeric2
- POWER(numeric1, numeric2)
• Table API:
- NUMERIC1 + NUMERIC2
- NUMERIC1.power(NUMERIC2)函数(Functions)
➢ 字符串函数
• SQL:
- string1 || string2
- UPPER(string)
- CHAR_LENGTH(string)
• Table API:
- STRING1 + STRING2
- STRING.upperCase()
- STRING.charLength()
➢ 时间函数
• SQL:
- DATE string
- TIMESTAMP string
- CURRENT_TIME
- INTERVAL string range
• Table API:
- STRING.toDate
- STRING.toTimestamp
- currentTime()
- NUMERIC.days
- NUMERIC.minutes
➢ 聚合函数
• SQL:
- COUNT(*)
- SUM(expression)
- RANK()
- ROW_NUMBER()
• Table API:
- FIELD.count
- FIELD.sum0用户自定义函数(UDF)
• 用户定义函数(User-defined Functions,UDF)是一个重要的特性,它们显
著地扩展了查询的表达能力
• 在大多数情况下,用户定义的函数必须先注册,然后才能在查询中使用
• 函数通过调用 registerFunction()方法在 TableEnvironment 中注册。当用
户定义的函数被注册时,它被插入到 TableEnvironment 的函数目录中,这样
Table API 或 SQL 解析器就可以识别并正确地解释它标量函数(Scalar Functions)
• 用户定义的标量函数,可以将0、1或多个标量值,映射到新的标量值
• 为了定义标量函数,必须在 org.apache.flink.table.functions 中扩展基类
Scalar Function,并实现(一个或多个)求值(eval)方法
• 标量函数的行为由求值方法决定,求值方法必须公开声明并命名为 eval
class HashCode( factor: Int ) extends ScalarFunction {
def eval( s: String ): Int = {
s.hashCode * factor
}
}表函数(Table Functions)
• 用户定义的表函数,也可以将0、1或多个标量值作为输入参数;与标量函数不同
的是,它可以返回任意数量的行作为输出,而不是单个值
• 为了定义一个表函数,必须扩展 org.apache.flink.table.functions 中的基类
TableFunction 并实现(一个或多个)求值方法
• 表函数的行为由其求值方法决定,求值方法必须是 public 的,并命名为 eval
class Split(separator: String) extends TableFunction[(String, Int)]{
def eval(str: String): Unit = {
str.split(separator).foreach(
word => collect((word, word.length))
)
}}聚合函数(Aggregate Functions)
• 用户自定义聚合函数(User-Defined Aggregate Functions,UDAGGs)可以
把一个表中的数据,聚合成一个标量值
• 用户定义的聚合函数,是通过继承 AggregateFunction 抽象类实现的聚合函数(Aggregate Functions)
• AggregationFunction要求必须实现的方法:
– createAccumulator()
– accumulate()
– getValue()
• AggregateFunction 的工作原理如下:
– 首先,它需要一个累加器(Accumulator),用来保存聚合中间结果的数据结构;
可以通过调用 createAccumulator() 方法创建空累加器
– 随后,对每个输入行调用函数的 accumulate() 方法来更新累加器
– 处理完所有行后,将调用函数的 getValue() 方法来计算并返回最终结果表聚合函数(Table Aggregate Functions)
• 用户定义的表聚合函数(User-Defined Table Aggregate Functions,
UDTAGGs),可以把一个表中数据,聚合为具有多行和多列的结果表
• 用户定义表聚合函数,是通过继承 TableAggregateFunction 抽象类来实现的表聚合函数(Table Aggregate Functions)
• AggregationFunction 要求必须实现的方法:
– createAccumulator()
– accumulate()
– emitValue()
• TableAggregateFunction 的工作原理如下:
– 首先,它同样需要一个累加器(Accumulator),它是保存聚合中间结果的数据结
构。通过调用 createAccumulator() 方法可以创建空累加器。
– 随后,对每个输入行调用函数的 accumulate() 方法来更新累加器。
– 处理完所有行后,将调用函数的 emitValue() 方法来计算并返回最终结果。Q & A
Flink的Table API和Flink SQL 基本程序结构 Table API 和 SQL 的程序结构,与流式处理的程序结构十分类似 val tableEnv=。。。 // 创建表的执行环境 // 创建一张表,用于读取数据 tableEnv.connect(...).createTemporaryTable("inputTable") // 注册一张表,用于把计算结果输出 tableEnv.connect(...).createTemporaryTable("outputTable") // 通过 Table API 查询算子,得到一张结果表 val 阅读详情

相关推荐

Flink Table API和SQL的分析及使用(一)

Flink针对标准的流处理和批处理提供了两种关系型API:Table API 和 SQL。Table API 可以直接进行select、filter、join等操作;Flink SQL则是基于Apache Calcite实现标准的SQL,和SQL语言一致,适合大部分开发人员。 Flink Table API和SQL 捆绑在Flink-Table依赖中,如果要使用需要添加一下依赖: 以Flink 1...

s243471087的博客 1493

Flink实战四_TableAPI&SQL

Flink实战三_TableAPI&SQL

core815的专栏 1861

详解 Flink Table API 和 Flink SQL 之函数

UDF 显著地扩展了查询的表达能力,可以解决一些系统内置函数无法解决的需求。使用步骤为:自定义 UDF 函数类继承 UserDefinedFunction 抽象类;创建 UDF 实例并在环境中调用 registerFunction() 方法注册;在 Table API 或 SQL 中使用。

weixin_44480009的博客 1467

Flink TableAPI与SQL

Flink的Table API与SQL的应用

a805814077的博客 825

Flink Table API和SQL

一、Table API和SQL的基本使用 想使用Table API和SQL,首先要创建一个TableEnvironment。TableEnvironment对象是Table API和SQL集成的核心,通过TableEnvironment可以实现以下功能。 •通过内部目录创建表。 •通过外部目录创建表。 •执行SQL查询。 •注册一个用户自定义的Function。 •把DataStream或者DataSet转换成Table。 •持有ExecutionEnvironment或者StreamExecution.

科学的N次方 366

Flink Table API & SQL 基本操作

Flink 版本:1.13.5 本文主要展示了 Table API 和 SQL 程序的常见结构,如何创建注册 Table,查询 Table,以及如何输出 Table。 1. Table API & SQL 程序结构 在 Flink 中,Table API 和 SQL 可以看作联结在一起的一套 API,这套 API 的核心概念是一个可以用作 Query 输入和输出的表 Table。在我们程序中,输入数据可以定义成一张表,然后对这张表进行查询得到一张新的表,最后还可以定义一张用于输出的表,负责将处理.

SmartSi 1647

【Flink】Flink Table API 和 SQL的介绍和使用,使用FlinkSQL实现实时topN

Flink 本身是批流统一的处理框架,所以 Table API 和 SQL,就是批流统一的上层处理 API。目前功能尚未完善,处于活跃的开发阶段。Table API 是一套内嵌在 Java 和 Scala 语言中的查询 API,它允许我们以非常直观的方式,组合来自一些关系运算符的查询(比如 select、filter 和 join)。而对于 Flink SQL,就是直接可以在代码中写 SQL,来实现一些查询(Query)操作。Flink 的 SQL 支持,基于实现了 SQL 标准的 Apache Calci

weixin_43923463的博客 1042

调试备忘录-SWD协议解析

目录--点击可快速直达 文章目录写在前面1  SWD协议简介2  SWD物理层协议解析2.1  SWD通信时序分析2.2  SWD 寄存器简介2.2.1  DP寄存器2.2.2  AP寄存器2.3  SWD通信流程2.3.1  SWD复位2.3.2  SWD读IDCODE2.3.3  SWD清除错误标志位,并且使能AP调试2.3.4  SWD读取AP IDR(也就是AP寄存器的ID CODE)2.3.5  SWD读写MCU任意寄存器 写在前面 最近由于公司需要,所以就做了个基于SWD协议的离线烧写器。由于.

洛神殇的博客 1万+

Flink之Table API&SQL详解

一、TableAPI&SQL的算子操作 1.1、初始化查询 下面的示例显示如何在已注册和内联的表上指定SQL查询。 val env = StreamExecutionEnvironment.getExecutionEnvironment val tableEnv = StreamTableEnvironment.create(env) // read a DataStr...

lixinkuan的博客 2642

Oracle Linux中/var/log/pcp/pmlogger目录膨胀问题分析与解决

本文详细分析了Oracle Linux系统中/var/log/pcp/pmlogger目录异常膨胀的常见原因与解决方案。当PCP性能监控框架的pmlogger服务日志轮转或清理机制失效时,会导致该目录无限增长,威胁系统稳定。文章提供了从服务状态诊断、配置文件审查到安全清理与预防策略的全流程实战指南,帮助运维人员快速回收磁盘空间并恢复服务正常运行。

weixin_29208327的博客 371

山东大学软件学院计算机组成原理课程设计实验三

文章目录一、实验时间二、实验内容1. 实验目的2. 设计要求3. 实验基本思路三、电路图1. 可预置初值的模256异步计数器2. 8位ALU电路3. 总图四、补充 一、实验时间 第三次实验:2021年4月8日星期四,第六周 第一次部件级实验,开始算分 二、实验内容 微程序控制的运算器设计 1. 实验目的 (1)熟悉简单运算器的结构 (2)熟悉微命令的产生和时序 (3)熟悉运算器功能测试。 2. 设计要求 利用之前设计的具有超前进位功能的8位ALU,实现简单算术或逻辑运算 两操作数由八位寄存器R0、R1提供,

叶卡捷琳堡的博客 1万+

Flink 流批一体深度解析:Table API & SQL 统一处理历史与实时数据

Flink流批一体技术解析 Apache Flink通过Table API和SQL实现了真正的流批一体处理能力。核心架构采用统一引擎,可自动切换批/流执行模式,关键组件包括: 统一接口:同一套Table API/SQL处理批数据和流数据 智能优化器:基于Calcite自动优化执行计划 自适应执行:根据数据源自动选择批/流模式 典型应用场景包括: 历史数据回填与实时更新统一处理 维表关联批流一体化 CDC变更数据统一管理 生产实践中可通过配置优化参数提升性能,如两阶段聚合、Join重排序等。状态管理支持TTL

csdn_tom_168的博客 1149

SAP Group Reporting入门指南(8)--业务操作

关于资产负债表类的匹配,系统预设了SGR01和SGR02两个方法,主要区别在于数据的来源范围,SGR01取自ACDOCA和ACDOCU,如果是0F类型的就会直接显示日记账分录(期间是000的除外,这类凭证是年结结转的,系统不再跨年追溯),如果是其他类型就显示合并分录。这里是我觉得SAP还需要优化的地方。基于ICMR的抵消任务中通常将抵销差异细分为交易差异、货币换算差异和其他差异,这在基于重分类抵消任务是无法实现的,基于重分类抵消只知道一个差异总额,很难从合并抵消凭证看出差异的来源,也没有审计线索可言。

bflyfish的博客 275

【Flink】Table API和SQL API

Flink具有两个关系API - 表API和SQL - 用于统一流和批处理。Table API是Scala和Java的语言集成查询API,允许以非常直观的方式组合来自关系运算符的查询,例如选择,过滤和连接。无论输入是批输入还是流输入,任一接口中指定的查询都具有相同的语义并产生相同的结果。 flink版本:1.8.0 scala版本:2.11.8 1、使用maven引入相关依赖 &l...

hlp4207的博客 1381

运行codex时出现登录失败:failed to start login server: 以一种访问权限不允许的方式做了一个访问套接字的尝试。 (os error 10013) 解决方案

的本质是Windows 系统端口保留策略而非代码 bug。推荐使用方案一(调整动态端口范围),一劳永逸解决。如果你安装了 Docker Desktop 或启用了 WSL2,调整端口范围后记得检查相关服务是否正常运行。

一键难忘的博客 4154

NVIDIA Isaac GR00T N1 人形机器人强化学习入门教程(二)详细步骤

LeRobot 格式 1.1 加载数据集 要加载数据集,我们需要定义以下 3 项内容: 在数据中显示图像帧 我们还可以对 LeRobotSingleDataset 类中的数据进行一系列转换。下面展示了如何对数据进行转换。 现在看看应用转换后的数据有何不同。 例如,对状态和操作进行规范化和串联,对视频图像进行裁剪、调整大小和颜色抖动。 二、GR00T 推断 本教程介绍如何使用 GR00

2506_90492529的博客 3012

Flink Table API 和 Flink SQL

1. 简单介绍 1.1 什么是 Table API 和 Flink SQL Flink本身是批流统一的处理框架,所以Table API和SQL,就是批流统一的上层处理API。 目前功能尚未完善,处于活跃的开发阶段。 Table API是一套内嵌在Java和Scala语言中的查询API,它允许我们以非常直观的方式,组合来自一些关系运算符的查询(比如select、filter和join)。而对于Flink SQL,就是直接可以在代码中写SQL,来实现一些查询(Query)操作。Flink的SQL支持,基于实现了

pageniao的博客 933

老 Intel Mac mini 装 OpenClaw:低成本常年在线方案

老款Intel Mac mini部署OpenClaw方案摘要 本文详细介绍了如何利用老款Intel Mac mini低成本部署OpenClaw系统。方案推荐2011-2018款Mac mini,建议升级至16GB内存和SSD存储以提升性能。部署步骤包括:1)安装Ubuntu系统;2)配置Docker环境;3)通过docker-compose部署OpenClaw及其依赖组件(PostgreSQL和Redis);4)进行系统级和Docker层面的性能优化;5)设置开机自启动服务。该方案充分利用老款设备剩余价值,

一键难忘的博客 2476

Flink Table API和Flink SQL

简介 Flink Table API 是一套内嵌在java和scala中的查询api,他允许以非常直观的方式组合一些关系运算符的查询。 Flink SQL是基于实现了SQL标准的Apache Calcite。 目前Flink Table API和SQL还不是很完善。 例子: package com.ts.tabletest; import com.ts.flink.SensorReading; import org.apache.flink.streaming.api.datastream.DataSt

寒暄的博客 1102

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Flink Table API和SQL(上)

概述   Flink 提供了对于“表”处理的支持,这就是更高层级的应用API,在 Flink 中被称为Table API 和 SQL。Table API 顾名思义,就是基于“表”(Table)的一套 API,它是内嵌在 Java、 Scala 等语言中的一种声明式领域特定语言(DSL),也就是专门为处理表而设计的;在此基础上,Flink 还基于Apache Calcite 实现了对 SQL 的支持。这样一来,我们就可以在 Flink 程序中直接写 SQL 来实现处理需求了。   在 Flink 中这两种

mengxianglong123的博客 2201

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Flink的Table API 与SQL介绍及调用

1 概述    DataSetAPI和DateStreamAPI是基于整个Flink的运行时环境做操作处理的,Table API和SQL是在DateStreamAPI上又包了一层。对于新版本的Blink在DateStream基础上又包了一层实现了批流统一,上层执行环境都是基于流处理,做批流统一的查询。Table API是流处理和批处理通用的关系型API,与常规SQL语言中将查询指定为字符串不同,Table API查询是以Java或Scala中的语言嵌入样式来定义。 是一套内嵌在 Java 和 Scala 语

fighting 3393

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Flink Table API与SQL技术详解

标量函数(Scalar Function):如 ABS (), SUBSTRING (), CURRENT_TIMESTAMP ()聚合函数(Aggregate Function):如 SUM (), COUNT (), HAVING ()表值函数(Table Valued Function):如 CROSS JOIN LATERAL TABLE ()

猫猫头 1776

flink笔记11 Flink Table API和SQL的简单实例

Apache Flink有两个关系应用编程接口——the Table API and SQL,用于统一的流和批处理 The Table API and SQL相互无缝集成,与Flink的DataStream API无缝集成 1.Table API & SQL简介 Table API是流处理和批处理通用的关系型API,Table API可以基于流输入或者批输入来运行而不需要进行任何修改 flink根据使用的便捷性提供了三种API,自下而上是: Table API & SQL特..

weixin_43631997的博客 679

Flink Table API与SQL流数据处理实战

这段代码展示了如何使用Apache Flink的Table API和SQL处理流数据。首先,通过StreamExecutionEnvironment获取流处理环境,并从文件中读取数据流。接着,将数据流转换为SensorReading对象,并打印输出。然后,创建StreamTableEnvironment,将数据流转换为表,并使用Table API进行筛选操作。同时,通过SQL查询实现相同功能,并将结果转换回数据流输出。最后,启动流处理任务。代码还介绍了Flink的Table API和SQL的优势、流与表的转

渣渣盟的博客 3014

Flink实战(六) - Table API & SQL编程

1 意义 1.1 分层的 APIs & 抽象层次 Flink提供三层API。 每个API在简洁性和表达性之间提供不同的权衡,并针对不同的用例。 而且Flink提供不同级别的抽象来开发流/批处理应用程序 最低级抽象只提供有状态流。它通过Process Function嵌入到DataStream API中。它允许用户自由处理来自一个或多个流的事件,并使用一致的容错状态。此外,用户可以...

JavaEdge全是干货的技术号 5376
上一篇: Table API 和 Flink SQL
下一篇: 大数据面试题
一凡888
博客等级 码龄7年 1755粉丝 217原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一凡888

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值