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")
}
}