Flink入坑指南第五章 - 語法糖 view

Flink入坑指南系列文章,從實際例子入手,一步步引導用戶零基礎入門實時計算/Flink,併成長爲使用Flink的高階用戶。本文屬個人原創,僅做技術交流之用,筆者才疏學淺,如有錯誤,歡迎指正。

什麼是view(視圖):
視圖無非就是存儲在數據庫中並具有名字的 SQL 語句,或者說是以預定義的 SQL 查詢的形式存在的數據表的成分。視圖可以包含表中的所有列,或者僅包含選定的列。視圖可以創建自一個或者多個表,這取決於創建該視圖的 SQL 語句的寫法。
視圖,一種虛擬的表,允許用戶執行以下操作:

  • 以用戶或者某些類型的用戶感覺自然或者直觀的方式來組織數據;
  • 限制對數據的訪問,從而使得用戶僅能夠看到或者修改(某些情況下)他們需要的數據;
  • 從多個表中彙總數據,以產生報表。

(引自:極客學院)

Flink SQL兼容標準SQL,view的作用與標準SQL相同,有幾個特點:

  • 在Flink SQL中,view是一種臨時表
  • 與標準SQL一樣,視圖可以創建自一個或多個表/視圖
  • 視圖的結果不會進行持久化,僅作爲計算的中間結果進行傳輸
  • 視圖的數據也可以被輸出到結果表中

Flink SQL中,視圖的語法非常簡單,可參考:view語法。接下來我們通過一些例子來實際感受一下視圖的作用。

假設在IoT場景中,要過濾出兩個廠房中的傳感器的異常數據。兩個廠房的數據分別發到了datahub的兩個不同topic,需要將兩個datahub topic中異常數據過濾出來,再彙總。
原始數據結構如下:

  • date
  • hour
  • ip: device ip
  • event_id: 

DDL -- 定義輸入輸出數據的數據結構,具體語法請參見 datahub源表/結果表語法,維表相關語法詳見Flink SQL維表語法

-- source1 定義廠房1的topic的數據結構
create table fab1(
  `date` int,
  hour int,
  ip varchar,
  event_id BIGINT
) with (
  type='datahub',
  endPoint='xxxxxxxxx',
  project='xxxxxxxxxx',
  topic='topic1',
  accessId='xXXXXXXXX',
  accessKey='XXXXXXXXX'); 
  
 -- source2 定義廠房2的topic的數據結構
  create table fab2(
  `date` int,
  hour int,
  ip varchar,
  event_id BIGINT
) with (
  type='datahub',
  endPoint='xxxxxxxxx',
  project='xxxxxxxxxx',
  topic='topic2',
  accessId='xXXXXXXXX',
  accessKey='XXXXXXXXX');
  
  -- 定義結果表1的數據結構
  create table sink(
  `date` int,
  hour int,
  event_id bigint,
  event_cnt bigint
  ) with (
  type='datahub',
  endPoint='xxxxxxxxx',
  project='xxxxxxxxxx',
  topic='topic2',
  accessId='xXXXXXXXX',
  accessKey='XXXXXXXXX');
  
  -- 定義結果表2的數據結構
  create table sink(
  `date` int,
  hour int,
  event_id bigint,
  event_cnt bigint
  ) with (
  type='rds',
  url='xxxxxx',
  tableName='xxxxxx',
  userName='xxxxxx',
  password='xxxxxx'
);

  -- 維表
  CREATE TABLE device_whitelist (
  ip varchar,
  category varchar,
  PRIMARY KEY (ip),  -- 用作維表時,必須有聲明的主鍵。
  PERIOD FOR SYSTEM_TIME  -- 定義維表的變化週期
) with (
  type = 'rds',
  ...
)

寫法一,按照批處理系統/數據庫的思維來看,這個需求非常簡單:

insert into sink
select e.`ip`,e.`hour`,e.`date`,e.`event_id` from 
(
  select * from fab1
  where event_id='00001'
  union 
  select * from fab2
  where event_id='00001'
) e
JOIN device_whitelist FOR SYSTEM_TIME AS OF PROCTIME() AS d
ON e.`ip` = d.`ip`

寫法二,使用view,將各個複雜SQL模塊拆開:

-- 
CREATE VIEW view1(`date`,`hour`,`ip`,`event_id`) AS
SELECT * FROM fab1
WHERE event_id='00001'
UNION 
SELECT * FROM fab2
WHERE event_id='00001'

-- 
CREATE VIEW view2(`date`,`hour`,`ip`,`event_id`) AS
SELECT e.`date`,e.`hour`,e.`ip`,e.`event_id` FROM view1 e
JOIN device_whitelist FOR SYSTEM_TIME AS OF PROCTIME() AS d
ON e.`ip` = d.`ip`

-- INSERT INTO sink1
INSERT INTO sink1
SELECT * FROM view2

-- INSERT INTO sink2
INSERT INTO sink2
SELECT * FROM view1

Flink中SQL的數據是不斷動態變化的,特別是涉及到一些特殊語法(如window級連/嵌套等),需要分步調試每個SQL模塊的結果。如果用寫法一,會大大增加SQL調試難度。因此,使用Flink SQL,建議使用第二種寫法,用view將各個語法塊串聯,方便調試和排查問題。寫法一和寫法二最終生成的作業DAG圖都是一樣的,沒有任何區別。一個Flink SQL作業可以同時定義多個輸出表,結果可同時被輸出到多種數據源中。

如果在使用實時計算產品過程中有任何問題,歡迎在博客下方回覆交流。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章