Flink的Table API

Table API是流處理和批處理通用的關(guān)系型API,Table API可以基于流輸入或者批輸入來運(yùn)行而不需要進(jìn)行任何修改。Table API是SQL語言的超集并專門為Apache Flink設(shè)計(jì)的,Table API是Scala 和Java語言集成式的API。與常規(guī)SQL語言中將查詢指定為字符串不同,Table API查詢是以Java或Scala中的語言嵌入樣式來定義的,具有IDE支持如:自動完成和語法檢測。

Table API與Flink的SQL集成共享許多其API的概念和部分,請參考通用的概念和API來了解如何注冊table或者創(chuàng)建一個Table對象,Streaming Concepts頁討論了特殊的概念如:動態(tài)表和時間屬性。

接下來的例子中假設(shè)注冊了一個名叫Orders的表并有(a, b, c, rowtime)屬性,rowtime字段可以是流中的邏輯時間字段或者是批中的常規(guī)時間戳字段。

概述和實(shí)例

Table API可以用于Scala和Java中,Scala Table API利用了Scala表達(dá)式,Java Table API則是基于字符串來的,字符串會被解析并轉(zhuǎn)換成等價的表達(dá)式。

接下來的例子展示了Scala 和 Java Table API的不同之處,表程序是在批環(huán)境中執(zhí)行的,它掃描Orders表,根據(jù)a字段來分組,并計(jì)算每個分組的結(jié)果,表程序的結(jié)果轉(zhuǎn)換為一個Row類型的DataSet并打印出來。

Java Table API可以通過導(dǎo)入org.apache.flink.table.api.java.*來啟用,下面的例子展示了Java Table API程序如何構(gòu)建及表達(dá)式如何指定為字符串。

// 配置環(huán)境
ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
BatchTableEnvironment tEnv = TableEnvironment.getTableEnvironment(env);

// 在表環(huán)境中注冊O(shè)rders表
// ...

// 指定一個表程序
Table orders = tEnv.scan("Orders"); // schema (a, b, c, rowtime)

Table counts = orders
        .groupBy("a")
        .select("a, b.count as cnt");

// 結(jié)果轉(zhuǎn)換為 DataSet
DataSet<Row> result = tableEnv.toDataSet(counts, Row.class);
result.print();

Scala Table API可以通過導(dǎo)入org.apache.flink.api.scala._org.apache.flink.table.api.scala._包來啟用。

下面例子展示了Scala Table API如何構(gòu)建, Table屬性使用Scala表達(dá)式來引用,Scala表達(dá)式以`開頭:

import org.apache.flink.api.scala._
import org.apache.flink.table.api.scala._

// 配置環(huán)境
val env = ExecutionEnvironment.getExecutionEnvironment
val tEnv = TableEnvironment.getTableEnvironment(env)

//在表環(huán)境中注冊一個Orders表
// ...

// specify table program
val orders = tEnv.scan("Orders") // schema (a, b, c, rowtime)

val result = orders
               .groupBy('a)
               .select('a, 'b.count as 'cnt)
               .toDataSet[Row] // 轉(zhuǎn)換為 DataSet
               .print()

下面的例子展示了一個更加復(fù)雜的Table API程序,程序再次掃描Orders表,過濾空值,將a字符字段轉(zhuǎn)為小寫,并每小時計(jì)算一次產(chǎn)生一個平均費(fèi)用b:

// 配置環(huán)境
// ...

// 指定表程序
Table orders = tEnv.scan("Orders"); // schema (a, b, c, rowtime)

Table result = orders
        .filter("a.isNotNull && b.isNotNull && c.isNotNull")
        .select("a.lowerCase(), b, rowtime")
        .window(Tumble.over("1.hour").on("rowtime").as("hourlyWindow"))
        .groupBy("hourlyWindow, a")
        .select("a, hourlyWindow.end as hour, b.avg as avgBillingAmount");
// 配置環(huán)境
// ...

// 指定表程序
val orders: Table = tEnv.scan("Orders") // schema (a, b, c, rowtime)

val result: Table = orders
        .filter('a.isNotNull && 'b.isNotNull && 'c.isNotNull)
        .select('a.lowerCase(), 'b, 'rowtime)
        .window(Tumble over 1.hour on 'rowtime as 'hourlyWindow)
        .groupBy('hourlyWindow, 'a)
        .select('a, 'hourlyWindow.end as 'hour, 'b.avg as 'avgBillingAmount);

因?yàn)門able API是流數(shù)據(jù)和批數(shù)據(jù)統(tǒng)一的API,所有的示例程序都可以在批輸入或者流輸入中執(zhí)行而不需要修改程序。在兩種情況下都會產(chǎn)生相同的結(jié)果,使得流記錄不會延遲。

操作

Table API支持下面的操作,請注意并不是所有的操作都同時支持批程序和流程序,不支持的會被響應(yīng)的標(biāo)記出來。

Scan,Projection和Filter (掃描、映射和過濾)

操作 描述
Scan 與SQL中的FROM相似,對已注冊的表執(zhí)行掃描操作
Table orders = tableEnv.scan("Orders");
Select 與SQL的SELECT語義類似,執(zhí)行一個select操作
Table orders = tableEnv.scan("Orders");
Table result = orders.select("a, c as d");
你也可以使用(*)作為通配符,來查詢表中所有字段的值
Table result = orders.select("*");
As 重命名字段
Table orders = tableEnv.scan("Orders");
Table result = orders.as("x, y, z, t");
Where / Filter 與SQL中的WHERE類似,過濾不通過過濾謂詞的行
Table orders = tableEnv.scan("Orders");
Table result = orders.where("b === 'red'");
或者
Table orders = tableEnv.scan("Orders");
Table result = orders.filter("a % 2 === 0");
操作 描述
Scan 與SQL查詢的From類似,對注冊的表執(zhí)行掃描操作
val orders: Table = tableEnv.scan("Orders")
Select 與SQL腳本的SELECT類似,執(zhí)行一個select操作:
val orders: Table = tableEnv.scan("Orders")
val result = orders.select('a, 'c as 'd)
你可以使用(*)作為通配符,查詢表中的所有字段
val orders: Table = tableEnv.scan("Orders")
val result = orders.select('*)
As 重命名字段:
val orders: Table = tableEnv.scan("Orders").as('x, 'y, 'z, 't)
Where/Filter 與SQL的WHERE類似,過濾掉不滿足過濾謂詞的行
val orders: Table = tableEnv.scan("Orders")
val result = orders.filter('a % 2 === 0)或者val orders: Table = tableEnv.scan("Orders")
val result = orders.where('b === "red")

聚合

操作 描述
GroupBy 聚合 與SQL的GROUP BY類似,使用以下運(yùn)行的聚合運(yùn)算符對分組鍵上的行進(jìn)行分組,從而以組方式聚合行。
Table orders = tableEnv.scan("Orders");
Table result = orders.groupBy("a").select("a, b.sum as d");
GroupBy Window 聚合 對分組窗口上的表,進(jìn)行分組和聚合,可能會按一個或者多個key進(jìn)行分組
Table orders = tableEnv.scan("Orders");
Table orders = tableEnv.scan("Orders");
Table result = orders .window(Tumble.over("5.minutes").on("rowtime").as("w")) // define window
  .groupBy("a, w") // group by key and window
  .select("a, w.start, w.end, b.sum as d"); // access window properties and aggregate
Over Window 聚合 與SQL的OVER類似,根據(jù)前一行和后續(xù)行的窗口(范圍)為每行計(jì)算窗口聚合,參看over window獲取更多信息。
Table orders = tableEnv.scan("Orders");
Table result = orders
.window(Over
.partitionBy("a")
.orderBy("rowtime")
.preceding("UNBOUNDED_RANGE")
.following("CURRENT_RANGE")
.as("w")
.select("a, b.avg over w, b.max over w, b.min over w") // sliding aggregate
Distinct 與SQL的DISTINCT類似,返回不重合的記錄。
Table orders = tableEnv.scan("Orders");
Table result = orders.distinct();
操作 描述
GroupBy 聚合 與SQL的GROUP BY類似,使用以下運(yùn)行的聚合運(yùn)算符對分組鍵上的行進(jìn)行分組,從而以組方式聚合行。
val orders: Table = tableEnv.scan("Orders")
val result = orders.groupBy('a).select('a, 'b.sum as 'd)
GroupBy Window 聚合 對分組窗口上的表,進(jìn)行分組和聚合,可能會按一個或者多個key進(jìn)行分組
val orders: Table = tableEnv.scan("Orders")
val result: Table = orders
  .window(Tumble over 5.minutes on 'rowtime as 'w)
  .groupBy('a, 'w) // group by key and window
  .select('a, w.start, 'w.end, 'b.sum as 'd) // access window properties and aggregate
Over Window 聚合 與SQL的OVER類似,根據(jù)前一行和后續(xù)行的窗口(范圍)為每行計(jì)算窗口聚合,參看over window獲取更多信息。
val orders:Table = tableEnv.scan("Orders");
val result:Table = orders
  .window(Over
  .partitionBy("a")
  .orderBy("rowtime")
  .preceding("UNBOUNDED_RANGE")
  .following("CURRENT_RANGE")
  .as("w")
  .select("a, b.avg over w, b.max over w, b.min over w") // sliding aggregate
Distinct 與SQL的DISTINCT類似,返回不重合的記錄。
val orders:Table = tableEnv.scan("Orders");
val result:Table = orders.distinct();

Joins

操作 描述
Inner Join 與SQL的JOIN 類似,連接兩張表,兩張表必須具有不同的字段名稱,并且必須至少具有一個相等的連接謂詞,必須通過連接運(yùn)算符或使用where或filter運(yùn)算符來定義。
  Table left = tableEnv.fromDataSet(ds1, "a, b, c");
  Table right = tableEnv.fromDataSet(ds2, "d, e, f");
  Table result = left.join(right).where("a = d").select("a, b, e");
Left Outer Join 與SQL的LEFT OUTER JOIN類似,
Right Outer Join 與SQL的RIGHT OUTER JOIN類似,
Full Outer Join 與SQL的FULL OUTER JOIN 類似,
TableFunction Join 與SQL的TableFunction Join類似
TableFunction Left Outer Join 與SQL的TableFunction Left Outer Join類似
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容