Flink(1.11)高階程式設計——FlinkSQL
八、Flink SQL 程式設計
8.1 Table API
①建立表的執行環境
StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env);
②將流轉成動態表 ——> fromDataStream
Table sensorTable = tableEnv.fromDataStream(sensorDS, $("ts"), $("id"), $("vc").as("ergou"));
③使用TableAPI對動態表進行操作,返回一個結果表
Table resultTable = sensorTable
.where($("id").isEqual("sensor_1"))
.select($("id"), $("ergou"));
④ 1 將動態錶轉換成流,輸出 ——> toAppendStream \ toRetractStream
正常:toAppendStream
DataStream<Tuple2<String, Integer>> resultDS =
tableEnv
.toAppendStream(resultTable, TypeInformation.of(new TypeHint<Tuple2<String, Integer>>() {}));
撤回流:toRetractStream
涉及到資料的更新,要使用 撤回流
// 撤回流實現方式:
// 前面加一個boolean型別的標誌位: true表示插入,false表示撤回
// 更新的邏輯: 將 舊的結果 置為 false,將 新的結果 插入,置為 true
// DataStream<Tuple2<Boolean, Row>> resultDS = tableEnv.toRetractStream(resultTable, Row.class);
DataStream<Tuple2<Boolean, Row>> resultDS =
tableEnv
.toRetractStream(resultTable, Row.class);
④ 2 將動態流寫入檔案系統 ——> executeInsert
1)、把檔案系統抽象成Table:Connect
1.呼叫connect,連線外部系統
2.呼叫withFormat,指定資料格式
3.呼叫withSchema,指定抽象成Table的表結構(欄位名,欄位型別)
4.呼叫creatTemporaryTable,指定Table的表名
tableEnv
.connect(new FileSystem().path("output/flink.txt"))
.withFormat(new OleCsv().filedDelimiter("|"))
.withSchema(
new Schema()
.field("a", DataTypes.STRING())
.field("tt", DataTypes.BIGINT())
.field("cc", DataTypes.INT())
)
.createTemporaryTable("fsTable");
2)、通過往表插入資料的方法,把結果Sink到檔案系統 ——> executeInsert
TableResult fsTable = resultTable.executeInsert("fsTable");
8.2 SQL API
① 建立表的執行環境
StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env);
② 將流轉換成動態表 ——> createTemporaryView
tableEnv.createTemporaryView("sensor", sensorDS, $("id"), $("ts"), $("vc"));
tableEnv.createTemporaryView("sensor1", sensorDS1, $("id"), $("ts"), $("vc"));
可以通過名字獲取Table物件
Table sensorTable = tableEnv.from("sensor");
③ 使用SQL對動態表進行操作,返回一個結果表 ——> sqlQuery
在 sqlQuery( ) 方法裡寫sql語句
Table resultTable = tableEnv
.sqlQuery("select * from sensor where id='sensor_1'"); // 條件查詢
//.sqlQuery("select id,count(id) cnt from sensor group by id"); // 分組查詢
//.sqlQuery("select * from sensor right join sensor1 on sensor.id=sensor1.id"); // 分組查詢
//.sqlQuery("select * from sensor where id not in (select id from sensor1)"); // 範圍查詢
//.sqlQuery("select (case id when 'sensor_1' then 1 else 0 end) test from sensor"); // case when查詢
返回一個結果表
tableEnv.createTemporaryView("result", resultTable);
④ 1 將動態錶轉換成流,輸出 ——> toRetractStream
DataStream<Tuple2<Boolean,Row>> resultDS = tableEnv.toRetractStream(resultTable,Row.class)
④ 2 將其寫入外部系統
1)、使用SQL將外部系統抽象成Table
tableEnv.executeSql("create table fsTable (a String,b bigint,c int) " +
"with (" +
"'connector'='filesystem'," +
"'path'='output'," +
"'format'='csv'" +
")");
2)、對其進行寫入,相當於sink到外部系統 ——> executeSql
關鍵字Bug:result =》 1.要麼避免和關鍵字重複 2.要麼加 ’ '
tableEnv.executeSql("insert into fsTable select * from 'result'");
8.3 FlinkSQL 整合Hive
〇 引數準備
String catalogName = "myhive"; //catalog名稱
String defaultDatabase = "flinktest"; // hive資料庫,設定為這個catalog下的預設庫
String hiveConfDir = "F:\\atguigu\\01_course\\code\\hive-conf"; // hive配置檔案所在的目錄
//String hiveConfDir = "/opt/module/hive/conf"; // hive配置檔案所在的目錄
String version = "1.2.1";
①建立hive的catalog
HiveCatalog hiveCatalog = new HiveCatalog(catalogName, defaultDatabase, hiveConfDir, version);
②註冊catalog
tableEnv.registerCatalog(catalogName,hiveCatalog);
③指定catalog(不指定,就是一個預設的catalog,叫default_catalog)
tableEnv.useCatalog(catalogName);
④ 指定sql語法為Hive sql
tableEnv.getConfig().setSqlDialect(SqlDialect.HIVE);
⑤使用sql操作hive表
//將流轉成一個動態表
tableEnv.createTemporaryView("inputTable", inputDS);
//執行sql語句
tableEnv.executeSql("insert into test select * from inputTable");
8.4 視窗
8.4.1 分組視窗(Group Windows)
〇 準備
//建立表的執行環境
StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env);
//將流轉換成動態表,並給表去個別名
tableEnv.createTemporaryView("sensor",sensorDS,$("id"), $("ts").rowtime(), $("vc"));
//獲取該表的物件
Table sensorTable = tableEnv.from("sensor");
① 滾動視窗
概念
1. over:定義視窗長度
2. on:用來分組(按時間間隔)或者排序(按行數)的時間欄位
3. as:別名,必須出現在後面的groupBy中
Table API 寫法
sensorTable
.window(Tumble.over(lit(3).seconds()).on($("ts").as("w"))
② 滑動視窗
概念
1. over:定義視窗長度
2. every:定義滑動步長
3. on:用來分組(按時間間隔)或者排序(按行數)的時間欄位
4. as:別名,必須出現在後面的groupBy中
Table API 寫法
sensorTable .window(Slide.over(lit(3).seconds()).every(lit(2).seconds()).on($("ts")).as("w"));
③ 會話視窗
概念
1. withGap:會話時間間隔
2. on:用來分組(按時間間隔)或者排序(按行數)的時間欄位
3. as:別名,必須出現在後面的groupBy中
Table API 寫法
sensorTable
.groupBy($("w"),$("id"))
.select($("id").count().as("cnt"),$("w").start(),$("w").end());
④SQL 寫法 【時間引數不加s】
// TODO 3.使用 SQL 對 Table 開 GroupWindow
Table resultTable = tableEnv.sqlQuery(
"select id,count(id) cnt," +
"TUMBLE_START(ts,INTERVAL '3' SECOND) as window_start," +
"TUMBLE_END(ts,INTERVAL '3' SECOND) as window_end " +
"from sensor " +
"group by TUMBLE(ts,INTERVAL '3' SECOND),id"
);
⑤ 將動態錶轉換成撤回流
tableEnv.toRetractStream(resultTable,Row.class).print();
8.4.2 Over Windows
概念
Group Windows在SQL查詢的Group BY子句中定義。與使用常規GROUP BY子句的查詢一樣,使用GROUP BY子句的查詢會計算每個組的單個結果行。
SQL支援以下Group視窗函式:
TUMBLE(time_attr, interval)
定義一個滾動視窗,第一個引數是時間欄位,第二個引數是視窗長度。
HOP(time_attr, interval, interval)【必須寫在groupby裡面】
定義一個滑動視窗,第一個引數是時間欄位,第二個引數是視窗滑動步長,第三個是視窗長度。
SESSION(time_attr, interval)
定義一個會話視窗,第一個引數是時間欄位,第二個引數是視窗間隔(Gap)。
另外還有一些輔助函式,可以用來選擇Group Window的開始和結束時間戳,以及時間屬性。
這裡只寫TUMBLE_*,滑動和會話視窗是類似的(HOP_*,SESSION_*)。
TUMBLE_START(time_attr, interval)
TUMBLE_END(time_attr, interval)
TUMBLE_ROWTIME(time_attr, interval)
TUMBLE_PROCTIME(time_attr, interval)
程式碼
//獲取表執行環境
StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env);
//將流轉表,並給表起一個名字
tableEnv.createTemporaryView("sensor", sensorDS, $("id"), $("ts").rowtime(), $("vc"));
//獲取表物件
Table sensorTable = tableEnv.from("sensor");
Table API 寫法
sensorTable.window(
Over
.partitionBy($("id"))
.orderBy($("ts").desc())
.preceding(UNBOUNDED_ROW)
.following(CURRENT_ROW)
.as("ow")
)
.select($("*"),$("id").count().over($("ow")));
SQL 寫法
Table resultTable = tableEnv.sqlQuery(
"select *," +
"count(id) over(partition by id order by ts desc) as cow\n" +
"from sensor"
);
//錶轉流
tableEnv.toRetractStream(resultTable, Row.class).print();
env.execute();
8.5 案例實操
熱門商品統計 TopN
public static void main(String[] args) throws Exception {
// 1.建立執行環境
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
// 2.讀取資料
SingleOutputStreamOperator<UserBehavior> userBehaviorDS = env
.readTextFile("input/UserBehavior.csv")
.map(new MapFunction<String, UserBehavior>() {
@Override
public UserBehavior map(String value) throws Exception {
String[] datas = value.split(",");
return new UserBehavior(
Long.valueOf(datas[0]),
Long.valueOf(datas[1]),
Integer.valueOf(datas[2]),
datas[3],
Long.valueOf(datas[4])
);
}
})
.assignTimestampsAndWatermarks(
WatermarkStrategy
.<UserBehavior>forBoundedOutOfOrderness(Duration.ofMinutes(1))
.withTimestampAssigner((data, ts) -> data.getTimestamp() * 1000L)
);
// TODO 3.使用 FlinkSQL 實現
//flinkSQL只支援blinkplanner
EnvironmentSettings settings = EnvironmentSettings.newInstance()
.useBlinkPlanner()
.inStreamingMode()
.build();
//blink基於流的模式
StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env, settings);
// 統計 每5分鐘輸出最近一小時的熱門商品點選,只需要 商品ID、行為、時間戳
Table userBehaviorTable = tableEnv.fromDataStream(userBehaviorDS,$("itemId"), $("behavior"), $("timestamp").rowtime().as("ts"));
// 3.1 資料的準備:過濾出pv行為、分組、開窗、求和統計、攜帶視窗資訊
Table aggTable = userBehaviorTable.where($("behavior").isEqual("pv"))
.window(
Slide
.over(lit(1).hours()).every(lit(5).minutes())
.on($("ts"))
.as("w")
)
.groupBy($("w"), $("itemId"))
.select($("itemId"),
$("itemId").count().as("itemCount"),
$("w").end().as("windowEnd"));
//把Table轉成DataStream,再轉成Table
DataStream<Row> aggDS = tableEnv.toAppendStream(aggTable, Row.class);
tableEnv.createTemporaryView("aggTable",aggDS,$("itemId"),$("itemCount"),$("windowEnd"));
//3.2 實現TopN
Table tableResult = tableEnv.sqlQuery(
"select * " +
"from (" +
"select *,row_number() over(partition by windowEnd order by itemCount desc) as rn from aggTable) " +
"where rn <= 3");
tableEnv.toRetractStream(tableResult, Row.class).print();
env.execute();
}
相關文章
- Oracle 高階程式設計 01 ~Oracle程式設計
- Python 高階程式設計:深入探索高階程式碼實踐Python程式設計
- 低階程式設計師和高階程式設計師的區別程式設計師
- windows核心程式設計--DLL高階Windows程式設計
- Javascript高階程式設計 備忘JavaScript程式設計
- C++高階程式設計pdfC++程式設計
- JavaScript高階程式設計筆記JavaScript程式設計筆記
- 重讀《JavaScript高階程式設計》JavaScript程式設計
- Python高階程式設計技巧Python程式設計
- shell程式設計-高階變數程式設計變數
- 高階bash指令碼程式設計(1)指令碼程式設計
- shell程式設計,實戰高階進階教學程式設計
- unix環境高階程式設計(中)-程式篇程式設計
- unix環境高階程式設計(下)-高階IO和程式間通訊篇程式設計
- 【北京】誠聘java程式設計師和高階程式設計師Java程式設計師
- Flink程式設計套路程式設計
- js高階程式設計 - 溫故而知新JS程式設計
- 《JavaScript 高階程式設計》精讀筆記JavaScript程式設計筆記
- 《JavaScript高階程式設計》筆記:DOM(十)JavaScript程式設計筆記
- 高階程式設計師到底強在哪裡?程式設計師
- Javascript高階程式設計 學習筆記JavaScript程式設計筆記
- JavaSE高階程式設計之多執行緒Java程式設計執行緒
- [心得]APUE高階程式設計知識整理程式設計
- 高階bash/shell指令碼程式設計指南指令碼程式設計
- 第31章:高階型別程式設計型別程式設計
- 如何成為高階java程式設計師Java程式設計師
- WebGL程式設計指南(8)高階技術Web程式設計
- 怎樣才能叫高階程式設計師?程式設計師
- 《javascript高階程式設計》筆記:文件模式JavaScript程式設計筆記模式
- 讀javascript高階程式設計04-canvasJavaScript程式設計Canvas
- 【極客班】Swift高階程式設計二Swift程式設計
- javascript高階程式設計第二章JavaScript程式設計
- 《Ext JS高階程式設計》即將上市!JS程式設計
- 如何從初級程式設計師變成高階程式設計師?程式設計師
- Java高階程式設計筆記 • 【第4章 網路程式設計】Java程式設計筆記
- IOS高階程式設計之三:IOS 多執行緒程式設計iOS程式設計執行緒
- 程式設計師的那些事兒 -- 高階程式設計師買衣服程式設計師
- 為什麼高階程式設計師討厭程式設計面試? - Adam程式設計師面試