Flink的流处理API(二)
一、Environment
1,getExecutionEnvironment
getExecutionEnvironment会根据查询运行的方式决定返回什么样的运行环境,是最常用的一种创建执行环境的方式。
2,createLocalEnvironment
返回本地执行环境,需要在调用时指定默认的并行度。
val env = StreamExecutionEnvironment.createLocalEnvironment() //parallelism
3,createRemoteEnvironment
返回集群执行环境,将Jar提交到远程服务器。需要在调用时指定JobManager的IP和端口号,并指定要在集群中运行的Jar包。
//hostname port jarFiles
val env = ExecutionEnvironment.createRemoteEnvironment(host, port,"/flink/wc.jar")
4,maven依赖
<dependencies>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-scala_2.</artifactId>
<version>1.7.</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-streaming-scala_2.</artifactId>
<version>1.7.</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-connector-kafka-.11_2.</artifactId>
<version>1.7.</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 该插件用于将Scala代码编译成class文件 -->
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>3.4.</version>
<executions>
<execution>
<!-- 声明绑定到maven的compile阶段 -->
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
二、Source
1,基本读取方式
//文件中读取
val fileDs = env.readTextFile("in/tbStock.txt")
//端口读取
val socketDs = env.socketTextStream("localhost",)
//集合中获取
val collectDs = env.fromCollection(List("aaa","bbb","ccc","aaa"))
2,kafka source
//kafka配置文件
val properties = new Properties()
properties.setProperty("bootstrap.servers", "hadoop102:9092")
properties.setProperty("group.id", "consumer-group")
properties.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer")
properties.setProperty("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer")
properties.setProperty("auto.offset.reset", "latest")
//接收kafka的topic-demo这个topic发来的数据
val kafkaDataStream: DataStream[String] = env.addSource(new FlinkKafkaConsumer011[String]("topic-demo", new SimpleStringSchema(), properties))
3,Flink Kafa如何实现exactly-once
可参考: https://www.aboutyun.com/forum.php?mod=viewthread&tid=27395
Flink通过checkpoint来保存数据是否处理完成的状态
由JobManager协调各个TaskManager进行checkpoint存储,checkpoint保存在 StateBackend中,默认StateBackend是内存级的,也可以改为文件级的进行持久化保存。
执行过程实际上是一个两段式提交,每个算子执行完成,会进行“预提交”,直到执行完sink操作,会发起“确认提交”,如果执行失败,预提交会放弃掉。
如果宕机需要通过StateBackend进行恢复,只能恢复所有确认提交的操作。

4,自定义source
env.addSource(new MySource)
//自定义source
class MySource extends SourceFunction[(String,Double)] {
//flag: 表示数据源是否还在正常运行
var running: Boolean = true
override def cancel(): Unit = {
running = false
}
override def run(ctx: SourceFunction.SourceContext[(String,Double)]): Unit = {
//初始化一个随机数发生器
val rand = new Random()
var curTemp = .to().map(
i => ("item_" + i, + rand.nextGaussian() * )
)
while (running) {
curTemp.foreach(
t => ctx.collect(t)
)
Thread.sleep() //每5秒钟产生一组数据
}
}
}
三、Transform
1,基本转换算子
//map
val streamMap = stream.map { x => x * }
//flatmap
val streamFlatMap = stream.flatMap{
x => x.split(" ")
}
//filter
val streamFilter = stream.filter{
x => x ==
}
2,KeyBy与Reduce
keyBy(DataStream → KeyedStream):输入必须是Tuple类型,逻辑地将一个流拆分成不相交的分区,每个分区包含具有相同key的元素,在内部以hash的形式实现的。
reduce(KeyedStream → DataStream):一个分组数据流的聚合操作,合并当前的元素和上次聚合的结果,产生一个新的值,返回的流中包含每一次聚合的结果,而不是只返回最后一次聚合的最终结果。
val keyedStream: KeyedStream[(String, Int), Tuple] = startUplogDstream.map(startuplog=>(startuplog.ch,)).keyBy()
//reduce //sum
keyedStream.reduce{ (ch1,ch2)=>
(ch1._1,ch1._2+ch2._2)
}.print()
3,Split和Select
split(DataStream → SplitStream):根据某些特征把一个DataStream拆分成两个或者多个DataStream。
select(SplitStream→DataStream):从一个SplitStream中获取一个或者多个DataStream。
//根据Item的id进行拆分
val splitStream:SplitStream[Item] = dStream.split {
item =>
List(item.id)
}
//获取标记为item_1的数据集
splitStream.select("item_1").print()
4,Connect和CoMap
connect(DataStream,DataStream → ConnectedStreams):连接两个保持他们类型的数据流,两个数据流被Connect之后,只是被放在了一个同一个流中,内部依然保持各自的数据和形式不发生任何变化,两个流相互独立。
CoMap,CoFlatMap(ConnectedStreams → DataStream):作用于ConnectedStreams上,功能与map和flatMap一样,对ConnectedStreams中的每一个Stream分别进行map和flatMap处理。
val connStream: ConnectedStreams[StartUpLog, StartUpLog] = appStoreStream.connect(otherStream)
val allStream: DataStream[String] = connStream.map(
(log1: StartUpLog) => log1.ch,
(log2: StartUpLog) => log2.ch
)
4,Union
DataStream → DataStream:对两个或者两个以上的DataStream进行union操作,产生一个包含所有DataStream元素的新DataStream。注意:如果你将一个DataStream跟它自己做union操作,在新的DataStream中,你将看到每一个元素都出现两次。
val unionStream: DataStream[StartUpLog] = appStoreStream.union(otherStream)
unionStream.print("union:::")
5,Connect与 Union 区别:
1)Union之前两个流的类型必须是一样,Connect可以不一样,在之后的coMap中再去调整成为一样的。
2)Connect只能操作两个流,Union可以操作多个
四、实现UDF函数
1,函数类(Function Classes)
Flink暴露了所有udf函数的接口(实现方式为接口或者抽象类)。例如:MapFunction, FilterFunction, ProcessFunction 等等。
val flinkTweets = tweets.filter(new FlinkFilter)
//自定义filter类
class FlinkFilter extends FilterFunction[String] {
override def filter(value: String): Boolean = { value.contains("flink")
}
}
2,匿名函数(Lamda Functions)
val flinkTweets = tweets.filter(_.contains("flink"))
3,富含数(Rich Functions)
富函数是 DataStream API 提供的一个函数类的接口,所有 Flink 函数类都有其 Rich 版本。它与常规函数的不同在于,可以获取运行环境的上下文,并拥有一些生命周期方法,所以可以实现更复杂的功能。
open()方法是 rich function 的初始化方法,当一个算子例如map或者filter被调用之前open()会被调用。
close()方法是生命周期中的最后一个调用的方法,做一些清理工作。
getRuntimeContext()方法提供了函数的 RuntimeContext 的一些信息,例如函数执行的并行度,任务的名字,以及 state 状态。
五、Sink
Flink 没有类似于spark中foreach方法,让用户进行迭代的操作。虽有对外的输出操作都要利用Sink完成。最后通过类似如下方式完成整个任务最终输出操作。
1,kafka
dstream.addSink(new FlinkKafkaProducer011[String]("linux01:9092","test", new SimpleStringSchema()))
2,redis
<dependency>
<groupId>org.apache.bahir</groupId>
<artifactId>flink-connector-redis_2.</artifactId>
<version>1.0</version>
</dependency>
val config = new FlinkJedisPoolConfig.Builder().setHost("127.0.0.1").setPort().build()
resultDStream.addSink(new RedisSink[Item](config,new MyRedisMapper))
//定义redisMapper
class MyRedisMapper extends RedisMapper[Item] {
override def getCommandDescription: RedisCommandDescription = {
new RedisCommandDescription(RedisCommand.HSET,"item_test") //hkey
}
override def getKeyFromData(data: Item): String = data.id
override def getValueFromData(data: Item): String = data.toString
}
3,Elasticsearch
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-connector-elasticsearch6_2.</artifactId>
<version>1.7.</version>
</dependency>
//定义es的host集合
val list = new util.ArrayList[HttpHost]()
list.add(new HttpHost("linux01", ))
//定义esBuilder
val esBuilder = new ElasticsearchSink.Builder[Item](list,new ElasticsearchSinkFunction[Item] {
override def process(element: Item, ctx: RuntimeContext, indexer: RequestIndexer): Unit = {
//定义es数据存储方式和存储值
val json = new util.HashMap[String, String]()
json.put("data", element.toString)
//定义存储索引 type 和数据源
val indexRequest = Requests.indexRequest().index("indexName").`type`("_doc").source(json)
indexer.add(indexRequest)
}
})
resultDStream.addSink(esBuilder.build())
4,自定义sink(JDBC)
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.</version>
</dependency>
resultDStream.addSink(new MyJDBCSink)
//自定义jdbcsink
class MyJDBCSink extends RichSinkFunction[Sensor]{
var conn: Connection = _
var insertStmt: PreparedStatement = _
var updateStmt: PreparedStatement = _
//open 简历连接
override def open(parameters: Configuration): Unit = {
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "")
insertStmt = conn.prepareStatement("INSERT INTO item_test (id, num) VALUES (?, ?)")
updateStmt = conn.prepareStatement("UPDATE item_test SET num = ? WHERE id = ?")
}
//调用执行
override def invoke(value: Sensor, context: SinkFunction.Context[_]): Unit = {
updateStmt.setDouble(, value.temp)
updateStmt.setString(, value.id)
updateStmt.execute()
if (updateStmt.getUpdateCount == ) {
insertStmt.setString(, value.id)
insertStmt.setDouble(, value.temp)
insertStmt.execute()
}
}
//关闭资源
override def close(): Unit = {
insertStmt.close()
updateStmt.close()
conn.close()
}
}
Flink的流处理API(二)的更多相关文章
- Flink 从0到1学习—— 分享四本 Flink 国外的书和二十多篇 Paper 论文
前言 之前也分享了不少自己的文章,但是对于 Flink 来说,还是有不少新入门的朋友,这里给大家分享点 Flink 相关的资料(国外数据 pdf 和流处理相关的 Paper),期望可以帮你更好的理解 ...
- 如何在 Apache Flink 中使用 Python API?
本文根据 Apache Flink 系列直播课程整理而成,由 Apache Flink PMC,阿里巴巴高级技术专家 孙金城 分享.重点为大家介绍 Flink Python API 的现状及未来规划, ...
- 《基于Apache Flink的流处理》读书笔记
前段时间详细地阅读了 <Apache Flink的流处理> 这本书,作者是 Fabian Hueske&Vasiliki Kalavri,国内崔星灿翻译的,这本书非常详细.全面得介 ...
- Flink在流处理上常见的Source和sink操作
flink在流处理上的source和在批处理上的source基本一致.大致有4大类 1.基于本地集合的source(Collection-based-source) 2.基于文件的source(Fil ...
- flink的流处理特性
flink的流处理特性: 支持高吞吐.低延迟.高性能的流处理 支持带有事件时间的窗口(Window)操作 支持有状态计算的Exactly-once语义 支持高度灵活的窗口(Window)操作,支持基于 ...
- Flink的DataSource三部曲之二:内置connector
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- Flink的sink实战之二:kafka
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- Civil 3D API二次开发学习指南
Civil 3D构建于AutoCAD 和 Map 3D之上,在学习Civil 3D API二次开发之前,您至少需要了解AutoCAD API的二次开发,你可以参考AutoCAD .NET API二次开 ...
- 用JSON-server模拟REST API(二) 动态数据
用JSON-server模拟REST API(二) 动态数据 上一篇演示了如何安装并运行 json server , 在这里将使用第三方库让模拟的数据更加丰满和实用. 目录: 使用动态数据 为什么选择 ...
随机推荐
- AIX系统下挂载外置存储
连接盘柜后在盘柜里映射好分区. 1.扫描硬件才能发现盘柜映射的容量 ,命令cfgmgr 2.查看在 AIX 系统下能否认到盘柜的分区. 命令:lsdev -Cc disk 3.查看物理卷(pv),命令 ...
- element-ui(vue版)使用switch时change回调函数中的形参传值问题
需求说明 有多个switch组件 需要知道switch的状态 表格中当前行(scope.row)的数据 问题描述 官方文档中对switch中change的描述: 目前能得到switch的状态值,但是无 ...
- Scala 基础(六):Scala变量 (三) 标识符
1 标识符概念 1) Scala 对各种变量.方法.函数等命名时使用的字符序列称为标识符 2) 凡是自己可以起名字的地方都叫标识符 2 标识符的命名规则 Scala中的标识符声明,基本和Java是一致 ...
- Mysql基础(三):MySQL基础数据类型、完整性约束、sql_mode模式
目录 2.MySQL基础数据类型.完整性约束.sql_mode模式 1. MySQL常用数据类型 2. 完整性约束 3. MySQL的sql_mode模式说明以及设置 2.MySQL基础数据类型.完整 ...
- 数据可视化之powerBI基础(一) 如何查看PowerBI图表背后的数据
https://zhuanlan.zhihu.com/p/64405494 图表很直观,但有时候我们不仅想看图,也想更进一步查看生成该图表的明细数据,在PowerBI中有三种方式. (一)在图表上单击 ...
- 数据可视化之PowerQuery篇(十二)客户购买频次分布
https://zhuanlan.zhihu.com/p/100070260 商业数据分析通常都可以简化为对数据进行筛选.分组.汇总的过程,本文通过一个实例来看看PowerBI是如何快速完成整个过程的 ...
- IDEA搭建SpringMVC简单接口框架(Maven项目)
1, 新建项目,选择Maven,如图一次选择,最后点击Next 2, 输入GroupId和ArtifactId,点击Next 3,根据需要选择自定义maven配置,点击Next.(①可以直接跳过) 4 ...
- Java8——方法引用
方法引用就是通过类名或方法名引用已经存在的方法来简化lambda表达式.那么什么时候需要用方法引用呢?如果lamdba体中的内容已经有方法实现了,我们就可以使用方法引用. 一.方法引用的三种语法格式 ...
- spring boot实现简单的登录拦截
一.思路 1.在pom.xml导入相关包 2.先写个简单的认证适配器(WebSecurityConfig extends WebSecurityConfigurerAdapter),登录拦截后就会跳转 ...
- Ethical Hacking - GAINING ACCESS(17)
CLIENT SIDE ATTACKS - Backdooring exe' s Download an executable file first. VEIL - FRAMEWORK A backd ...