一、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,ConnectUnion 区别:

  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(二)的更多相关文章

  1. Flink 从0到1学习—— 分享四本 Flink 国外的书和二十多篇 Paper 论文

    前言 之前也分享了不少自己的文章,但是对于 Flink 来说,还是有不少新入门的朋友,这里给大家分享点 Flink 相关的资料(国外数据 pdf 和流处理相关的 Paper),期望可以帮你更好的理解 ...

  2. 如何在 Apache Flink 中使用 Python API?

    本文根据 Apache Flink 系列直播课程整理而成,由 Apache Flink PMC,阿里巴巴高级技术专家 孙金城 分享.重点为大家介绍 Flink Python API 的现状及未来规划, ...

  3. 《基于Apache Flink的流处理》读书笔记

    前段时间详细地阅读了 <Apache Flink的流处理> 这本书,作者是 Fabian Hueske&Vasiliki Kalavri,国内崔星灿翻译的,这本书非常详细.全面得介 ...

  4. Flink在流处理上常见的Source和sink操作

    flink在流处理上的source和在批处理上的source基本一致.大致有4大类 1.基于本地集合的source(Collection-based-source) 2.基于文件的source(Fil ...

  5. flink的流处理特性

    flink的流处理特性: 支持高吞吐.低延迟.高性能的流处理 支持带有事件时间的窗口(Window)操作 支持有状态计算的Exactly-once语义 支持高度灵活的窗口(Window)操作,支持基于 ...

  6. Flink的DataSource三部曲之二:内置connector

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  7. Flink的sink实战之二:kafka

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  8. Civil 3D API二次开发学习指南

    Civil 3D构建于AutoCAD 和 Map 3D之上,在学习Civil 3D API二次开发之前,您至少需要了解AutoCAD API的二次开发,你可以参考AutoCAD .NET API二次开 ...

  9. 用JSON-server模拟REST API(二) 动态数据

    用JSON-server模拟REST API(二) 动态数据 上一篇演示了如何安装并运行 json server , 在这里将使用第三方库让模拟的数据更加丰满和实用. 目录: 使用动态数据 为什么选择 ...

随机推荐

  1. 将PDF转化为wrod

    public static void CreateWord(string HtmlPath, string WordSavePath) { string inputName = HtmlPath; / ...

  2. mybitis下choose..when. otherwise条件不起作用

    我的代码如下: <select id="findList" resultType="TyArticle"> SELECT <include r ...

  3. adb devices 不能连接设备 could not install *smartsocket* listener

    cmd以管理员身份运行命令adb devices  或adb reverse tcp:8081 tcp:8081,无法连接设备,出现上图信息. 输入命令:adb kill-server 再输入:adb ...

  4. Qt_Demo3:实现棋盘

    1  简介 参考视频:https://www.bilibili.com/video/BV1XW411x7NU?p=53 说明:实现一个8*8的棋盘,点击棋盘的任意位置显示一个表情,并打印出当前的坐标( ...

  5. Alexnet网络结构

    最近试一下kaggle的文字检测的题目,目前方向有两个ssd和cptn.直接看看不太懂,看到Alexnet是基础,今天手写一下网络,记录一下啊. 先理解下Alexnet中使用的原件和作用: 激活函数使 ...

  6. Unity- 小“东西”

    菜单栏遍历处理预制体工具 public class GameEditor : Editor { private static void ProcessPrefabs(Action<GameObj ...

  7. DEX文件解析--4、dex类的类型解析

    一.前言   前几篇系列文章链接:     DEX文件解析---1.dex文件头解析     DEX文件解析---2.Dex文件checksum(校验和)解析     DEX文件解析--3.dex文件 ...

  8. Ethical Hacking - GAINING ACCESS(14)

    CLIENT SIDE ATTACKS Protecting against smart delivery methods Ensure you're not being MITM'ed -> ...

  9. Makefile中的一个坑

    问题描述:Makefile中,我想将一个变量的后缀全部进行替换,如将所有的.c后缀变成.d后缀 方法:$(CUR_SOURCE: .c = .d ) 说明:查阅相关资料,了解到上述这种语法就可以将所有 ...

  10. Vue使用定时器定时刷新页面

    1. 需求说明 在前端开发中,往往会遇到页面需要实时刷新数据的情况,给用户最新的数据展示. 2. 逻辑分析 如果需要数据实时更新,我们自然是需要使用定时器,不断的调用接口数据,会相对的消耗内存. 3. ...