Table API 和 SQL 程序的结构
所有用于批处理和流处理的 Table API 和 SQL 程序都遵循相同的模式。下面的代码示例展示了 Table API 和 SQL 程序的通用结构
// 创建TableEnvironment
val tableEnv = ...
// 创建表
tableEnv.connect(...).createTemporaryTable("table1")
// 注册一张输出表
tableEnv.connect(...).createTemporaryTable("outputTable")
// 通过Table API query创建表
val tapiResult = tableEnv.from("table1").select(...)
// 通过SQL query创建表
val sqlResult = tableEnv.sqlQuery("SELECT ... FROM table1 ...")
// 将Table API结果表发送到TableSink,与SQL结果相同
TableResult tableResult = tapiResult.executeInsert("outputTable");
tableResult...
// execute
tableEnv.execute("scala_job")
创建 TableEnvironment
TableEnvironment
是 Table API 和 SQL 的核心概念。它负责:
- 在内部的 catalog 中注册
Table
- 注册外部的 catalog
- 加载可插拔模块
- 执行 SQL 查询
- 注册自定义函数 (scalar、table 或 aggregation)
- 将
DataStream
或DataSet
转换成Table
- 持有对
ExecutionEnvironment
或StreamExecutionEnvironment
的引用
Table
总是与特定的 TableEnvironment
绑定。不能在同一条查询中使用不同 TableEnvironment 中的表,例如,对它们进行 join 或 union 操作。
TableEnvironment
可以通过静态方法 BatchTableEnvironment.create()
或者 StreamTableEnvironment.create()
在 StreamExecutionEnvironment
或者 ExecutionEnvironment
中创建,TableConfig
是可选项。TableConfig
可用于配置TableEnvironment
或定制的查询优化和转换过程
要确保选择与编程语言匹配的特定的计划器BatchTableEnvironment
/StreamTableEnvironment
。
如果两种计划器的 jar 包都在 classpath 中(默认行为),应该明确地设置要在当前程序中使用的计划器
// **********************
// FLINK STREAMING QUERY
// **********************
import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment
import org.apache.flink.table.api.EnvironmentSettings
import org.apache.flink.table.api.bridge.scala.StreamTableEnvironment
val fsSettings = EnvironmentSettings.newInstance().useOldPlanner().inStreamingMode().build()
val fsEnv = StreamExecutionEnvironment.getExecutionEnvironment
val fsTableEnv = StreamTableEnvironment.create(fsEnv, fsSettings)
// or val fsTableEnv = TableEnvironment.create(fsSettings)
// ******************
// FLINK BATCH QUERY
// ******************
import org.apache.flink.api.scala.ExecutionEnvironment
import org.apache.flink.table.api.bridge.scala.BatchTableEnvironment
val fbEnv = ExecutionEnvironment.getExecutionEnvironment
val fbTableEnv = BatchTableEnvironment.create(fbEnv)
// **********************
// BLINK STREAMING QUERY
// **********************
import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment
import org.apache.flink.table.api.EnvironmentSettings
import org.apache.flink.table.api.bridge.scala.StreamTableEnvironment
val bsEnv = StreamExecutionEnvironment.getExecutionEnvironment
val bsSettings = EnvironmentSettings.newInstance().useBlinkPlanner().inStreamingMode().build()
val bsTableEnv = StreamTableEnvironment.create(bsEnv, bsSettings)
// or val bsTableEnv = TableEnvironment.create(bsSettings)
// ******************
// BLINK BATCH QUERY
// ******************
import org.apache.flink.table.api.{EnvironmentSettings, TableEnvironment}
val bbSettings = EnvironmentSettings.newInstance().useBlinkPlanner().inBatchMode().build()
val bbTableEnv = TableEnvironment.create(bbSettings)
注意: 如果/lib
目录中只有一种计划器的 jar 包,则可以使用useAnyPlanner
(python 使用 use any_u_planner
)创建 EnvironmentSettings
。
在 Catalog 中创建表
TableEnvironment
维护着一个由标识符(identifier)创建的表 catalog 的映射。标识符由三个部分组成:catalog 名称、数据库名称以及对象名称。如果 catalog 或者数据库没有指明,就会使用当前默认值。
Table
可以是虚拟的(视图 VIEWS
)也可以是常规的(表 TABLES
)。
视图 VIEWS
可以从已经存在的Table
中创建,一般是 Table API 或者 SQL 的查询结果。
表TABLES
描述的是外部数据,例如文件、数据库表或者消息队列。
临时表(Temporary Table)和永久表(Permanent Table)
表可以是临时的,并与单个 Flink 会话(session)的生命周期相关,也可以是永久的,并且在多个 Flink 会话和群集(cluster)中可见。
永久表需要catalog以维护表的元数据。一旦永久表被创建,它将对任何连接到 catalog 的 Flink 会话可见且持续存在,直至被明确删除。
另一方面,临时表通常保存于内存中并且仅在创建它们的 Flink 会话持续期间存在。这些表对于其它会话是不可见的。它们不与任何 catalog 或者数据库绑定但可以在一个命名空间(namespace)中创建。即使它们对应的数据库被删除,临时表也不会被删除。
创建表
虚拟表
在 SQL 的术语中,Table API 的对象对应于视图
(虚拟表)。它封装了一个逻辑查询计划。它可以通过以下方法在 catalog 中创建:
// 获取TableEnvironment
val tableEnv = ...
// 通过简单投影查询得到表
val projTable: Table = tableEnv.from("X").select(...)
// 将表projTable注册为表“ projectedTable”
tableEnv.createTemporaryView("projectedTable", projTable)
注意: 定义了 Table
的查询是没有被优化的, 而且会被内嵌到另一个引用了这个注册了的 Table
的查询中。如果多个查询都引用了同一个注册了的Table
,那么它会被内嵌每个查询中并被执行多次, 也就是说注册了的Table
的结果不会被共享(注:Blink 计划器的TableEnvironment
会优化成只执行一次)。
Connector Tables
另外一个方式去创建 TABLE
是通过 connector 声明。Connector 描述了存储表数据的外部系统。存储系统例如 Apache Kafka 或者常规的文件系统都可以通过这种方式来声明
tableEnvironment
.connect(...)
.withFormat(...)
.withSchema(...)
.inAppendMode()
.createTemporaryTable("MyTable")
tableEnvironment.executeSql("CREATE [TEMPORARY] TABLE MyTable (...) WITH (...)")