Table API是用于流和批处理的统一关系API。Table API查询可以在批处理或流式输入上运行,无需修改。Table API是SQL语言的一个超级集合,专门为使用Apache Flink而设计。Table API是Scala和Java的语言集成API。Table API查询不是像SQL一样将查询指定为字符串值,而是以Java或Scala中嵌入的语言样式定义的,支持IDE,如自动完成和语法验证。
Table API与Flink的SQL集成共享许多概念和部分API。看看常见的概念&API,了解如何注册表或创建表对象。流概念页面讨论流特定的概念,如动态表和时间属性。
下面的示例假设一个名为Orders的注册表具有属性(a、b、c、rowtime)。rowtime字段可以是流式处理中的逻辑时间属性,也可以是批处理中的常规时间戳字段。
目录
- 一、概述和示例
- 二、操作
- 1、Scan, Projection, and Filter
- 2、Column Operations
- 3、聚合(Aggregations)
- 4、连接(Joins)
- 5、Set操作
- 6、OrderBy, Offset & Fetch
- 7、Insert
- 8、组窗口(Group Windows)
- 9、Tumble (Tumbling Windows)
- 10、Slide (Sliding Windows)
- 11、Session (Session Windows)
- 12、Over Windows
- 13、无界窗口(Unbounded Over Windows)
- 14、有界窗口(Bounded Over Windows)
- 15、基于行的操作(Row-based Operations)
- 三、数据类型
- 四、表达式语法
一、概述和示例
Table API可用于Scala和Java。Scala表API利用Scala表达式,Java表API基于字符串,字符串被解析并转换为等价的表达式。
下面的示例显示了Java表API相关代码信息。表程序在批处理环境中执行。它扫描Orders表,按字段a分组,并按组计算结果行数。table程序的结果被转换成Row类型的数据集并打印出来。
import org.apache.flink.table.api._
import org.apache.flink.table.api.java._
// environment configuration
ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
BatchTableEnvironment tEnv = BatchTableEnvironment.create(env);
// register Orders table in table environment
// ...
// specify table program
Table orders = tEnv.scan("Orders"); // schema (a, b, c, rowtime)
Table counts = orders
.groupBy("a")
.select("a, b.count as cnt");
// conversion to DataSet
DataSet<Row> result = tEnv.toDataSet(counts, Row.class);
result.print();
下一个例子展示了一个更复杂的表API程序。程序再次扫描Orders表。它过滤空值,规范化字符串类型的字段a,并为每个小时计算平均帐单金额b,并将其乘积a。
// environment configuration
// ...
// specify table program
Table orders = tEnv.scan("Orders"); // schema (a, b, c, rowtime)
Table result = orders
.filter("a.isNotNull && b.isNotNull && c.isNotNull")
.select("a.lowerCase() as a, b, rowtime")
.window(Tumble.over("1.hour").on("rowtime").as("hourlyWindow"))
.groupBy("hourlyWindow, a")
.select("a, hourlyWindow.end as hour, b.avg as avgBillingAmount");
由于表API是用于批处理和流式数据的统一API,因此两个示例程序都可以在批处理和流式输入上执行,而无需修改表程序本身。在这两种情况下,程序都会产生相同的结果,前提是流记录不会延迟(有关详细信息,请参见流概念)。
二、操作
Table API支持以下操作。请注意,并非所有操作都可以在批处理和流式处理中使用;它们会相应地进行标记。
1、Scan, Projection, and Filter
2、Column Operations
3、聚合(Aggregations)
4、连接(Joins)
5、Set操作
6、OrderBy, Offset & Fetch
7、Insert
8、组窗口(Group Windows)
组窗口根据时间或行计数间隔将行聚合到有限组中,并对每个组计算一次聚合函数。对于批处理表,窗口是按时间间隔对记录进行分组的方便快捷方式。
Windows是使用window(w:GroupWindow)子句定义的,需要使用as子句指定的别名。为了按窗口对表进行分组,必须在group by(…)子句中像常规分组属性一样引用窗口别名。下面的示例演示如何在表上定义窗口聚合。
在流式处理环境中,只有当窗口聚合在窗口之外的一个或多个属性上分组时,才能并行计算窗口聚合,即groupBy(…)子句引用窗口别名和至少一个附加属性。仅引用窗口别名的groupBy(…)子句(如上面的示例)只能由单个非并行任务计算。下面的示例演示如何使用其他分组属性定义窗口聚合。
窗口属性(如时间窗口的开始、结束或行时时间戳)可以作为窗口别名的属性(分别为w.start、w.end和w.rowtime)添加到select语句中。窗口开始时间戳和行时时间戳是包含的上下窗口边界。相反,窗口结束时间戳是独占的窗口上边界。例如,从下午2点开始的30分钟滚动窗口将有14:00:00.000作为开始时间戳,14:29:59.999作为行时间戳,14:30:00.000作为结束时间戳。
窗口参数定义如何将行映射到窗口。窗口不是用户可以实现的接口。相反,表API提供了一组具有特定语义的预定义窗口类,这些窗口类被转换为底层数据流或数据集操作。下面列出了支持的窗口定义。
9、Tumble (Tumbling Windows)
翻滚窗口将行分配给固定长度的不重叠连续窗口。例如,5分钟的翻滚窗口以5分钟的间隔对行进行分组。翻转窗口可以在事件时间、处理时间或行计数上定义。
使用Tumble类定义翻滚窗口,如下所示:
10、Slide (Sliding Windows)
滑动窗口具有固定大小,并按指定的滑动间隔滑动。如果滑动间隔小于窗口大小,则滑动窗口重叠。因此,可以将行分配给多个窗口。例如,15分钟大小和5分钟滑动间隔的滑动窗口将每行指定给3个15分钟大小的不同窗口,这些窗口的计算间隔为5分钟。滑动窗口可以在事件时间、处理时间或行计数上定义。
滑动窗口通过使用Slide类定义如下:
11、Session (Session Windows)
会话窗口的大小不是固定的,但它们的界限是由不活动的间隔定义的,即,如果在定义的间隔期内没有事件出现,会话窗口将关闭。例如,间隔为30分钟的会话窗口在30分钟不活动后观察到一行时启动(否则该行将添加到现有窗口中),如果在30分钟内没有添加行,则该窗口将关闭。会话窗口可以在事件时间或处理时间上工作。
会话窗口通过使用会话类定义如下:
12、Over Windows
Over-window聚合是标准SQL(Over子句)中已知的,并在查询的SELECT子句中定义。与GROUPBY子句中指定的group windows不同,over windows不折叠行。相反,over window aggregates计算相邻行范围内每个输入行的聚合。
Over windows使用window(w:overwindows*)子句(在Python API中使用Over_window(*overwindows))定义,并通过select()方法中的别名引用。下面的示例演示如何在表上定义over-window聚合。
overwindows定义了计算聚合的一系列行。overwindows不是用户可以实现的接口。相反,表API提供Over类来配置Over窗口的属性。可以在事件时间或处理时间以及指定为时间间隔或行计数的范围内定义Over windows。支持的over-window定义作为over(和其他类)上的方法公开,如下所示:
注意:当前,同一select()调用中的所有聚合函数都必须在同一个over window中计算。
13、无界窗口(Unbounded Over Windows)
14、有界窗口(Bounded Over Windows)
15、基于行的操作(Row-based Operations)
基于行的操作生成具有多个列的输出。
三、数据类型
请参阅有关数据类型的专用页。
泛型类型和(嵌套的)复合类型(例如pojo、元组、行、Scala case类)也可以是行的字段。
可以使用值访问函数访问具有任意嵌套的复合类型的字段。
泛型类型被视为一个黑盒,可以由用户定义的函数传递或处理。