GitHub
https://github.com/SmallScorpion/flink-tutorial.git
將 DataStream 轉換成表
Flink允許我們把Table和DataStream做轉換:我們可以基於一個DataStream,先流式地讀取數據源,然後map成樣例類,再把它轉成Table。Table的列字段(column fields),就是樣例類裏的字段,這樣就不用再麻煩地定義schema了。
import com.atguigu.bean.SensorReading
import org.apache.flink.streaming.api.scala._
import org.apache.flink.table.api.{DataTypes, Table}
import org.apache.flink.table.api.scala._
object DataStreamToTableTest {
def main(args: Array[String]): Unit = {
val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
env.setParallelism(1)
// 創建表環境
val tableEnv: StreamTableEnvironment = StreamTableEnvironment.create(env)
val inputDStream: DataStream[String] = env.readTextFile("D:\\MyWork\\WorkSpaceIDEA\\flink-tutorial\\src\\main\\resources\\SensorReading.txt")
val dataDstream: DataStream[SensorReading] = inputDStream.map(
data => {
val dataArray: Array[String] = data.split(",")
SensorReading(dataArray(0), dataArray(1).toLong, dataArray(2).toDouble)
})
// 常規創建
val dataTable: Table = tableEnv.fromDataStream(dataDstream)
// Schema基於名稱
val sensorTable = tableEnv.fromDataStream(dataDstream,
'timestamp as 'ts, 'id as 'myId, 'temperature)
// Schema基於位置 一一對應
val sensorTable_lo = tableEnv.fromDataStream(dataDstream, 'myId, 'ts)
// 測試輸出
val resultTable: Table = dataTable
.select('id, 'temperature) // 查詢id和temperature字段
.filter('id === "sensor_1") // 輸出sensor_1得數據
resultTable.toAppendStream[ (String, Double) ].print( "data" )
env.execute(" table DS test job")
}
}
創建臨時視圖(Temporary View)
View和Table的Schema完全相同。事實上,在Table API中,可以認爲View和Table是等價的。
創建臨時視圖的第一種方式,就是直接從DataStream轉換而來。同樣,可以直接對應字段轉換;也可以在轉換的時候,指定相應的字段。
tableEnv.createTemporaryView("sensorView", dataStream)
tableEnv.createTemporaryView("sensorView", dataStream, 'id, 'temperature, 'timestamp as 'ts)
還可以基於Table創建視圖:
tableEnv.createTemporaryView("sensorView", sensorTable)
輸出表
- 表的輸出,是通過將數據寫入 TableSink 來實現的
- TableSink 是一個通用接口,可以支持不同的文件格式、存儲數據庫和消息隊列
- 輸出表最直接的方法,就是通過 Table.insertInto() 方法將一個 Table 寫入註冊過的 TableSink 中
tableEnv.connect(...)
.createTemporaryTable("outputTable")
val resultSqlTable: Table = ...
resultTable.insertInto("outputTable")
輸出到文件
import org.apache.flink.streaming.api.scala._
import org.apache.flink.table.api.{DataTypes, Table}
import org.apache.flink.table.api.scala._
import org.apache.flink.table.descriptors.{FileSystem, OldCsv, Schema}
object SinkToFileSystemTest {
def main(args: Array[String]): Unit = {
val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
env.setParallelism(1)
// 創建表環境
val tableEnv: StreamTableEnvironment = StreamTableEnvironment.create(env)
// --------------------- 讀取文件數據 ---------------------------
val filePath = "D:\\MyWork\\WorkSpaceIDEA\\flink-tutorial\\src\\main\\resources\\SensorReading.txt"
tableEnv.connect( new FileSystem().path(filePath) ) // 定義表的數據來源,和外部系統建立連接
.withFormat( new OldCsv() ) // 定義從外部文件讀取數據之後的格式化方法
.withSchema( new Schema() // 定義表結構
.field("id", DataTypes.STRING())
.field("timestamp", DataTypes.BIGINT())
.field("temperature", DataTypes.DOUBLE())
)
.createTemporaryTable( "fileInputTable" ) // 在表環境中註冊一張表(創建)
val sensorTable: Table = tableEnv.from( "fileInputTable" )
val resultTable: Table = sensorTable
.select('id, 'temperature) // 查詢id和temperature字段
.filter('id === "sensor_1") // 輸出sensor_1得數據
resultTable.toAppendStream[ (String, Double) ].print( "FileSystem" )
env.execute(" table connect fileSystem test job")
}
}
輸出到Kafka
除了輸出到文件,也可以輸出到Kafka。我們可以結合前面Kafka作爲輸入數據,構建數據管道,kafka進,kafka出。
import org.apache.flink.streaming.api.scala._
import org.apache.flink.table.api.{DataTypes, Table}
import org.apache.flink.table.api.scala._
import org.apache.flink.table.descriptors.{Csv, Kafka, Schema}
object SinkToKafkaTest {
def main(args: Array[String]): Unit = {
val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
env.setParallelism(1)
// 創建表環境
val tableEnv: StreamTableEnvironment = StreamTableEnvironment.create(env)
// --------------------- 消費Kafka數據 ---------------------------
tableEnv.connect( new Kafka()
.version( "0.11" ) // 版本
.topic( "sensor" ) // 主題
.property("zookeeper.connect", "hadoop102:2181")
.property("bootstrap.servers", "hadoop102:9092")
)
.withFormat( new Csv() ) // 新版本得Csv
.withSchema( new Schema()
.field("id", DataTypes.STRING())
.field("timestamp", DataTypes.BIGINT())
.field("temperature", DataTypes.DOUBLE())
)
.createTemporaryTable( "kafkaInputTable" )
// 查詢
val sensorTable: Table = tableEnv.from( "kafkaInputTable" )
val resultTable: Table = sensorTable
.select('id, 'temperature) // 查詢id和temperature字段
.filter('id === "sensor_1") // 輸出sensor_1得數據
// 定義輸出的Kafka結構
tableEnv.connect( new Kafka()
.version( "0.11" ) // 版本
.topic( "sensor_out" ) // 主題
.property("zookeeper.connect", "hadoop102:2181")
.property("bootstrap.servers", "hadoop102:9092")
)
.withFormat( new Csv() ) // 新版本得Csv
.withSchema( new Schema()
.field("id", DataTypes.STRING())
.field("temperature", DataTypes.DOUBLE())
)
.createTemporaryTable( "kafkaOutputTable" )
// 查詢結果輸出到Kafka中
resultTable.insertInto("kafkaOutputTable")
env.execute(" kafka pipeline test job")
}
}