Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
周六在深圳分享了《Flink SQL 1.9.0 技術(shù)內(nèi)幕和最佳實(shí)踐》,會后許多小伙伴對最后演示環(huán)節(jié)的 Demo 代碼非常感興趣,迫不及待地想嘗試下,所以寫了這篇文章分享下這份代碼。希望對于 Flink SQL 的初學(xué)者能有所幫助。
這份代碼主要由兩部分組成:1) 能用來提交 SQL 文件的 SqlSubmit 實(shí)現(xiàn)。2) 用于演示的 SQL 示例、Kafka 啟動停止腳本、 一份測試數(shù)據(jù)集、Kafka 數(shù)據(jù)源生成器。
通過本實(shí)戰(zhàn),你將學(xué)到:
SqlSubmit 的實(shí)現(xiàn)
筆者一開始是想用 SQL Client 來貫穿整個演示環(huán)節(jié),但可惜 1.9 版本 SQL CLI 還不支持處理 CREATE TABLE 語句。所以筆者就只好自己寫了個簡單的提交腳本。后來想想,也挺好的,可以讓聽眾同時了解如何通過 SQL 的方式,和編程的方式使用 Flink SQL。
SqlSubmit 的主要任務(wù)是執(zhí)行和提交一個 SQL 文件,實(shí)現(xiàn)非常簡單,就是通過正則表達(dá)式匹配每個語句塊。如果是 CREATE TABLE 或 INSERT INTO 開頭,則會調(diào)用 tEnv.sqlUpdate(...)。如果是 SET 開頭,則會將配置設(shè)置到 TableConfig 上。其核心代碼主要如下所示:
使用 DDL 連接 Kafka 源表
在 flink-sql-submit 項目中,我們準(zhǔn)備了一份測試數(shù)據(jù)集(來自阿里云天池公開數(shù)據(jù)集,特別鳴謝),位于 src/main/resources/user_behavior.log。數(shù)據(jù)以 JSON 格式編碼,大概長這個樣子:
{"user_id": "543462", "item_id":"1715", "category_id": "1464116", "behavior": "pv", "ts": "2017-11-26T01:00:00Z"} {"user_id": "662867", "item_id":"2244074", "category_id": "1575622", "behavior": "pv", "ts": "2017-11-26T01:00:00Z"}
為了模擬真實(shí)的 Kafka 數(shù)據(jù)源,筆者還特地寫了一個 source-generator.sh 腳本(感興趣的可以看下源碼),會自動讀取 user_behavior.log 的數(shù)據(jù)并以默認(rèn)每毫秒1條的速率灌到 Kafka 的 user_behavior topic 中。
有了數(shù)據(jù)源后,我們就可以用 DDL 去創(chuàng)建并連接這個 Kafka 中的 topic(詳見 src/main/resources/q1.sql)。
注:可能有用戶會覺得其中的 connector.properties.0.key 等參數(shù)比較奇怪,社區(qū)計劃將在下一個版本中改進(jìn)并簡化 connector 的參數(shù)配置。
使用 DDL 連接 MySQL 結(jié)果表
連接 MySQL 可以使用 Flink 提供的 JDBC connector。例如
PV UV 計算
假設(shè)我們的需求是計算每小時全網(wǎng)的用戶訪問量,和獨(dú)立用戶數(shù)。很多用戶可能會想到使用滾動窗口來計算。但這里我們介紹另一種方式。即 Group Aggregation 的方式。
INSERT INTO pvuv_sink SELECT DATE_FORMAT(ts, 'yyyy-MM-dd HH:00') dt, COUNT(*) AS pv, COUNT(DISTINCT user_id) AS uv FROM user_log GROUP BY DATE_FORMAT(ts, 'yyyy-MM-dd HH:00')
它使用 DATE_FORMAT 這個內(nèi)置函數(shù),將日志時間歸一化成“年月日小時”的字符串格式,并根據(jù)這個字符串進(jìn)行分組,即根據(jù)每小時分組,然后通過 COUNT(*) 計算用戶訪問量(PV),通過 COUNT(DISTINCT user_id) 計算獨(dú)立用戶數(shù)(UV)。這種方式的執(zhí)行模式是每收到一條數(shù)據(jù),便會進(jìn)行基于之前計算的值做增量計算(如+1),然后將最新結(jié)果輸出。所以實(shí)時性很高,但輸出量也大。
我們將這個查詢的結(jié)果,通過 INSERT INTO 語句,寫到了之前定義的 pvuv_sink MySQL 表中。
注:在深圳 Meetup 中,我們有對這種查詢的性能調(diào)優(yōu)做了深度的介紹。
環(huán)境準(zhǔn)備
本實(shí)戰(zhàn)演示環(huán)節(jié)需要安裝一些必須的服務(wù),包括:
1.下載 Flink 1.9.0 安裝包并解壓:https://www.apache.org/dist/flink/flink-1.9.0/flink-1.9.0-bin-scala_2.11.tgz
2.下載以下依賴 jar 包,并拷貝到 flink-1.9.0/lib/ 目錄下。因為我們運(yùn)行時需要依賴各個 connector 實(shí)現(xiàn)。
3.將 flink-1.9.0/conf/flink-conf.yaml 中的 taskmanager.numberOfTaskSlots 修改成 10,因為我們的演示任務(wù)可能會消耗多于1個的 slot。
4.在 flink-1.9.0 目錄下執(zhí)行 ./bin/start-cluster.sh,啟動集群。
運(yùn)行成功的話,可以在 http://localhost:8081 訪問到 Flink Web UI。
另外,還需要將 Flink 的安裝路徑填到 flink-sql-submit 項目的 env.sh 中,用于后面提交 SQL 任務(wù),如我的路徑是
FLINK_DIR=/Users/wuchong/dev/install/flink-1.9.0
Kafka 本地集群安裝
下載 Kafka 2.2.0 安裝包并解壓:https://www.apache.org/dist/kafka/2.2.0/kafka_2.11-2.2.0.tgz
將安裝路徑填到 flink-sql-submit 項目的 env.sh 中,如我的路徑是
KAFKA_DIR=/Users/wuchong/dev/install/kafka_2.11-2.2.0
在 flink-sql-submit 目錄下運(yùn)行 ./start-kafka.sh 啟動 Kafka 集群。
在命令行執(zhí)行 jps,如果看到 Kafka 進(jìn)程和 QuorumPeerMain 進(jìn)程即表明啟動成功。
MySQL 安裝
可以在官方頁面下載 MySQL 并安裝:
https://dev.mysql.com/downloads/mysql/
如果有 Docker 環(huán)境的話,也可以直接通過 Docker 安裝
https://hub.docker.com/_/mysql
$ docker pull mysql $ docker run --name mysqldb -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql
然后在 MySQL 中創(chuàng)建一個 flink-test 的數(shù)據(jù)庫,并按照上文的 schema 創(chuàng)建 pvuv_sink 表。
提交 SQL 任務(wù)
1.在 flink-sql-submit 目錄下運(yùn)行 ./source-generator.sh,會自動創(chuàng)建 user_behavior topic,并實(shí)時往里灌入數(shù)據(jù)。
2.在 flink-sql-submit 目錄下運(yùn)行 ./run.sh q1, 提交成功后,可以在 Web UI 中看到拓?fù)洹?/p>
在 MySQL 客戶端,我們也可以實(shí)時地看到每個小時的 pv uv 值在不斷地變化
本文帶大家搭建基礎(chǔ)集群環(huán)境,并使用 SqlSubmit 提交純 SQL 任務(wù)來學(xué)習(xí)了解如何連接外部系統(tǒng)。flink-sql-submit/src/main/resources/q1.sql 中還有一些注釋掉的調(diào)優(yōu)參數(shù),感興趣的同學(xué)可以將參數(shù)打開,觀察對作業(yè)的影響。關(guān)于這些調(diào)優(yōu)參數(shù)的原理,可以看下我在 深圳 Meetup 上的分享《Flink SQL 1.9.0 技術(shù)內(nèi)幕和最佳實(shí)踐》。
作者:巴蜀真人
HTML 表格:<table> 標(biāo)簽定義 。
簡單的 HTML 表格包括: table 元素,一個或多個 tr、th 以及 td 元素。
<table border=1px;> <tr> <th> row1,col1 </th><th>row1,col2 </th> </tr> <tr> <th> row2,col1 </th><td>row2,col2 </td> </tr> </table>
tr(行標(biāo)簽)、 th(表頭單元格標(biāo)簽)、 td(普通單元格標(biāo)簽) caption(表格標(biāo)題)、 col(定義列)、 colgroup(對表格中的列進(jìn)行組合)、thead(組合表頭的內(nèi)容) tbody(組合表格的主題內(nèi)容) 、tfoot(組合表格的腳注內(nèi)容) 等
<td>(普通單元格標(biāo)簽) : 元素定義表格單元格
<td>11,980</td>
<th>(表頭單元格標(biāo)簽) : 元素定義表格表頭
<th scope="row">工資</th>
<tr>(行標(biāo)簽) : 元素定義表格行
<tr> <th scope="row">工資</th> <td>11,980</td> <td>12,650</td> <td>9,700</td> <td>10,600</td> <td rowspan="5">工作</td> </tr>
<caption>(表格標(biāo)題):元素定義表格標(biāo)題
<caption class="c1">月度收入4月 - 7月 </caption>
還有一些復(fù)雜的表格才能用到的元素 :<col>、 <colgroup>、<thead>、 <tbody> 、<tfoot>等.
由于thead, tbody, tfoot是從語義 上來劃分 表格結(jié)構(gòu)的, 主要用于比較復(fù)雜的表格中。
<colspan>合并行元素 :定義<table>中的行的合并
<td colspan="5">153,629</td>
<rowspan>合并列元素 :定義<table>中的列的合并
<td rowspan="5">工作</td>
<table>表格的嵌套:
<tr> <th scope="row">總計</th> <td>36,060</td> <td>38,759</td> <td>38,110</td> <td>40,700</td> <td class="ct"> <table id="t2"> <tr><td></td></tr> </table> </td> </tr>
嵌套
HTML基礎(chǔ)表格的應(yīng)用,上面的簡單元素就可以滿足,運(yùn)用表格邏輯思維去思考,可以更快的掌握<table>表格標(biāo)簽。
本文部分圖片來自網(wǎng)絡(luò),如有侵權(quán),請聯(lián)系修改。
在HTML/CSS 中,我們經(jīng)常用HTML來布局和填充內(nèi)容,用CSS來添加效果,修飾內(nèi)容和布局,使整個頁面變得更好看。
即在<head></head>標(biāo)簽內(nèi)添加CSS樣式表的鏈接:
代碼展示如下:
<head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Make a Table Frame</title> <link rel="stylesheet" type="text/css" href="CSS/tableframe.css" > </head>
定義:
對帶有指定屬性的 HTML 元素設(shè)置樣式。
注意:
只有在規(guī)定了 !DOCTYPE 時,IE7 和 IE8 才支持屬性選擇器。在 IE6 及更低的版本中,不支持屬性選擇。
功能:
“選擇器”指明了{(lán)}中的“樣式”的作用對象,也就是“樣式”作用于網(wǎng)頁中的哪些元素。
CSS中的選擇器有三個:
標(biāo)簽選擇器、class類選擇器、id選擇器
1.標(biāo)簽選擇器樣式表:a{}、 div{}、table{} ...
{對全局所有的選中類型標(biāo)簽的樣式修改}
2.class類選擇器 樣式表: .class{}
{在HTML中每個標(biāo)簽都可以同時綁定多個類名,每個標(biāo)簽都可以設(shè)置class;同一個界面中class是不可重復(fù)}
3. id選擇器樣式表: #d1 {}
{每個標(biāo)簽都可有id,每個頁面不可重復(fù)id,}
【一個HTML標(biāo)簽只能綁定一個id屬性,一個HTML標(biāo)簽可以綁定多個class屬性】
單純選擇<div>標(biāo)簽的時候 是對全局的的(所有的)<div>進(jìn)行修飾;
選擇器優(yōu)先級:
id選擇器>class類選擇器>標(biāo)簽選擇器
所以有id和class 選擇器的標(biāo)簽將不會被覆蓋。交叉時是按照優(yōu)先級覆蓋顯示的。
單純的HTML 表格表單內(nèi)容
標(biāo)題<caption>標(biāo)簽:
表格的標(biāo)題<caption>的內(nèi)容填充(HTML):
<caption> 表格標(biāo)題</caption>
標(biāo)題<caption>的樣式修飾(CSS)
table.formdata caption { text-shadow: #FF00ff; text-align: center; padding-bottom: 6px; font-weight: bold; }
其他<table>標(biāo)簽相關(guān)內(nèi)容可參考 HTML中表格的實(shí)例應(yīng)用 一文。
form在網(wǎng)頁中主要負(fù)責(zé)數(shù)據(jù)采集功能。
一個表單有三個基本組成部分:
(1)表單標(biāo)簽:包含了處理表單數(shù)據(jù)所用CGI程序的URL以及數(shù)據(jù)提交到服務(wù)器的方法。
(2)表單域:包含了文本框、密碼框、隱藏域、多行文本框、復(fù)選框、單選框、下拉選擇框和文件上傳框等。
(3)表單按鈕:提交按鈕、復(fù)位按鈕和一般按鈕;用于將數(shù)據(jù)傳送到服務(wù)器上的CGI腳本或者取消輸入。還可以用表單按鈕來控制其他定義了處理腳本的處理工作。
定義:
<input> 標(biāo)簽規(guī)定用戶可輸入數(shù)據(jù)的輸入字段。
根據(jù)不同的 type 屬性,輸入字段有多種形態(tài)。輸入字段可以是文本字段、復(fù)選框、密碼字段、單選按鈕、按鈕等等
語法代碼:
<input type="value" >
實(shí)例代碼:
<td><input type="text" name="Mainboard 6月" id="Mainboard 6月"></td>
關(guān)系展示:
實(shí)例代碼:
<p>
<input type="submit" name="btnSubmit" id="btnSubmit" value="Add Data" class="btn">
<input type="reset" value="Reset All" class="btn">
</p>
實(shí)例展示:
<input>標(biāo)簽的其他屬性值:
input標(biāo)簽外是否添加form標(biāo)簽需要按情形區(qū)分:
應(yīng)用場景的區(qū)別:
1.所有向后臺提交數(shù)據(jù)(包括原生和ajax提交)的<input>都建議用<form>包裹.
2.如果只是用來做前臺交互效果則不推薦使用form包裹。
但提交數(shù)據(jù)時,其實(shí)也可以不用form包裹input標(biāo)簽:
1.如果有form標(biāo)簽,在點(diǎn)擊提交銨鈕時,瀏覽器自動收集參數(shù),并打包一個http請求到服務(wù)器,完成表單提交。在這一過程中,瀏覽器會根據(jù)method的不同,將參數(shù)編碼后,放在urI中(get),或者放在請求的data中(post)。然后發(fā)送到服務(wù)器。
2.如果沒有form,post方式的提交要使用ajax手工完成。get方式的提交需要自己拼接url。
<form>表單其他相關(guān)內(nèi)容可參考 HTML中 表單 的應(yīng)用實(shí)例 一文。
最后,附帶一下該可輸入的EXCEL表格的源碼。
HTML code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Make a Table Frame</title> <link rel="stylesheet" type="text/css" href="CSS/tableframe.css" > </head> <body image=""> <form method="psot"> <table border="1px" class="formdata"> <caption>電腦配件管理表2018年5月-8月</caption> <tr> <th></th> <th scope="col">5月</th> <th scope="col">6月</th> <th scope="col">7月</th> <th scope="col">8月</th> </tr> <tr> <th scope="row">Hard Disk</th> <td><input type="text" name="Hard Disk 5月" id="Hard Disk 5月"></td> <td><input type="text" name="Hard Disk 6月" id="Hard Disk 6月"></td> <td><input type="text" name="Hard Disk 7月" id="Hard Disk 7月"></td> <td><input type="text" name="Hard Disk 8月" id="Hard Disk 8月"></td> </tr> <tr> <th scope="row">Mainboard</th> <td><input type="text" name="Mainboard 5月" id="Mainboard 5月"></td> <td><input type="text" name="Mainboard 6月" id="Mainboard 6月"></td> <td><input type="text" name="Mainboard 7月" id="Mainboard 7月"></td> <td><input type="text" name="Mainboard 8月" id="Mainboard 8月"></td> </tr> <tr> <th scope="row">Case</th> <td><input type="text" name="Case 5月" id="Case 5月"></td> <td><input type="text" name="Case 6月" id="Case 6月"></td> <td><input type="text" name="Case 7月" id="Case 7月"></td> <td><input type="text" name="Case 8月" id="Case 8月"></td> </tr> <tr> <th scope="row">Power</th> <td><input type="text" name="Power 5月" id="Power 5月"></td> <td><input type="text" name="Power 6月" id="Power 6月"></td> <td><input type="text" name="Power 7月" id="Power 7月"></td> <td><input type="text" name="Power 8月" id="Power 8月"></td> </tr> <tr> <th scope="row">CPU Fan</th> <td><input type="text" name="CPU Fan 5月" id="CPU Fan 5月"></td> <td><input type="text" name="CPU Fan 6月" id="CPU Fan 6月"></td> <td><input type="text" name="CPU Fan 7月" id="CPU Fan 7月"></td> <td><input type="text" name="CPU Fan 8月" id="CPU Fan 8月"></td> </tr> <tr> <th scope="row">Total</th> <td><input type="text" name="Total 5月" id="Total 5月"></td> <td><input type="text" name="Total 6月" id="Total 6月"></td> <td><input type="text" name="Total7月" id="Total 7月"></td> <td><input type="text" name="Total 8月" id="Total 8月"></td> </tr> </table> <p> <input type="submit" name="btnSubmit" id="btnSubmit" value="Add Data" class="btn"> <input type="reset" value="Reset All" class="btn"> </p> </form> </body> </html>
CSS code :
body { font-family: Arial; /*background-image: url(image/mainroad.jpg) no-repeat;*/ background-color: #00ff00; background-size: 100%; } table.formdata { width: 300px; height: 150px; border: 2px solid #F00; border-collapse: collapse; font-family: Arial; } table.formdata caption { text-shadow: #FF00ff; text-align: center; padding-bottom: 6px; font-weight: bold; } table.formdata th { border:1px solid #be34hc; background-color: #E2E2E2; color:#000000; text-aglin:center; font-weight: normal; padding: 2px 8px 2px 6px; margin: 0px; } table.formdata input { width: 100px; padding: 1px 3px 1px 3px; margin: 0px; border:none; font-family: Arial; } .btn { width:100px; background-color: #FF00ee; border:1px solid #00f2f2; font-family: Arial; }
本文部分內(nèi)容來自網(wǎng)絡(luò),如有侵權(quán),請聯(lián)系修改。
*請認(rèn)真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。