1. Flink 批处理Api

1.1 Source

Flink+kafka是如何实现exactly-once语义的

  Flink通过checkpoint来保存数据是否处理完成的状态;

  有JobManager协调各个TaskManager进行checkpoint存储,checkpoint保存在 StateBackend中,默认StateBackend是内存级的,也可以改为文件级的进行持久化保存。

执行过程实际上是一个两段式提交,每个算子执行完成,会进行“预提交”,直到执行完sink操作,会发起“确认提交”,如果执行失败,预提交会放弃掉。

如果宕机需要通过StateBackend进行恢复,只能恢复所有确认提交的操作。

Spark中要想实现有状态的,需要使用updateBykey或者借助redis;

而Fink是把它记录在State Bachend,只要是经过keyBy等处理之后结果会记录在State Bachend(已处理未提交; 如果是处理完了就是已提交状态;),

它还会记录另外一种状态值:keyState,比如keyBy累积的结果;

StateBachend如果不想存储在内存中,也可以存储在fs文件中或者HDFS中; IDEA的工具只支持memory内存式存储,一旦重启就没了;部署到linux中就支持存储在文件中了;

Kakfa的自动提交:“enable.auto.commit”,比如从kafka出来后到sparkStreaming之后,一进来consumer会帮你自动提交,如果在处理过程中,到最后有一个没有写出去(比如写到redis、ES),虽然处理失败了但kafka的偏移量已经发生改变;所以移偏移量的时机很重要;

1.2 Transform  转换算子

map

val streamMap = stream.map { x => x *  }
object StartupApp {
def main(args: Array[String]): Unit = {
val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
val myKafkaConsumer: FlinkKafkaConsumer011[String] = MyKafkaUtil.getConsumer("GMALL_STARTUP")
val dstream: DataStream[String] = env.addSource(myKafkaConsumer) //dstream.print().setParallelism(1) 测试从kafka中获得数据是否打通到了flink中 //将json转换成json对象
val startupLogDStream: DataStream[StartupLog] = dstream.map { jsonString =>
JSON.parseObject(jsonString, classOf[StartupLog])
} //需求一 相同渠道的值进行累加
val sumDStream: DataStream[(String, Int)] = startupLogDStream.map { startuplog => (startuplog.ch, 1) }.keyBy(0)
    .reduce { (startuplogCount1, startuplogCount2) =>
val newCount: Int = startuplogCount1._2 + startuplogCount2._2
(startuplogCount1._1, newCount)
}
//val sumDStream: DataStream[(String, Int)] = startupLogDStream.map{startuplog => (startuplog.ch,1)}.keyBy(0).sum(1)
//sumDStream.print()
env.execute() }
}

flatMap

flatMap的函数签名:def flatMap[A,B](as: List[A])(f: A ⇒ List[B]): List[B]
例如: flatMap(List(,,))(i ⇒ List(i,i))
结果是List(,,,,,),
而List("a b", "c d").flatMap(line ⇒ line.split(" "))
结果是List(a, b, c, d) val streamFlatMap = stream.flatMap{
x => x.split(" ")
}

Filter

val streamFilter = stream.filter{
x => x ==
}

KeyBy

DataStream → KeyedStream:输入必须是Tuple类型,逻辑地将一个流拆分成不相交的分区,每个分区包含具有相同key的元素,在内部以hash的形式实现的。

以HashCode来进行分区,可能有些key值不相同也会分到相同区。

滚动聚合算子(Rolling Aggregation)

这些算子可以针对KeyedStream的每一个支流做聚合,必须KeyBy分组之后再sum聚合等。
sum()
min()
max()
minBy()
maxBy()

Reduce

KeyedStream → DataStream:一个分组数据流的聚合操作,合并当前的元素和上次聚合的结果,产生一个新的值,返回的流中包含每一次聚合的结果,而不是只返回最后一次聚合的最终结果。

val stream2 = env.readTextFile("YOUR_PATH\\sensor.txt")
.map( data => {
val dataArray = data.split(",")
SensorReading(dataArray().trim, dataArray().trim.toLong, dataArray().trim.toDouble)
})
.keyBy("id")
.reduce( (x, y) => SensorReading(x.id, x.timestamp + , y.temperature) )

Split 和 Select

DataStream 通过split得到→ SplitStream --->通过select得到DataStream:根据某些特征把一个DataStream拆分成两个或者多个DataStream。

SplitStream→DataStream从一个SplitStream中获取一个或者多个DataStream。

    //需求二   把 appstore   和其他的渠道的数据 分成两个流
val splitableStream: SplitStream[StartupLog] = startupLogDStream.split { startuplog =>
var flagList: List[String] = List()
if (startuplog.ch.equals("appstore")) {
flagList = List("apple")
} else {
flagList = List("other")
}
flagList
}
val appleStream: DataStream[StartupLog] = splitableStream.select("apple")
//appleStream.print("this is apple").setParallelism(1)
val otherdStream: DataStream[StartupLog] = splitableStream.select("other")
//otherdStream.print("this is other").setParallelism(1)

Connect和 CoMap

connecte的两条流数据类型可以不同,但一次操作只能合并2条流;

DataStream,DataStream → ConnectedStreams:连接两个保持他们类型的数据流,两个数据流被Connect之后,只是被放在了一个同一个流中,内部依然保持各自的数据和形式不发生任何变化,两个流相互独立。

ConnectedStreams → DataStream:作用于ConnectedStreams上,功能与map和flatMap一样,对ConnectedStreams中的每一个Stream分别进行map和flatMap处理。

 //需求三 把上面两个流合并为一个
val connStream: ConnectedStreams[StartupLog, StartupLog] = appleStream.connect(otherdStream)
val allDataStream: DataStream[String] = connStream.map((startuplog1: StartupLog) => startuplog1.ch, (startuplog2: StartupLog) => startuplog2.ch)
allDataStream.print("all").setParallelism(1)

 CoMap,CoFlatMap

    

ConnectedStreams → DataStream:作用于ConnectedStreams上,功能与map和flatMap一样,对ConnectedStreams中的每一个Stream分别进行map和flatMap处理。

val warning = high.map( sensorData => (sensorData.id, sensorData.temperature) )
val connected = warning.connect(low) val coMap = connected.map(
warningData => (warningData._1, warningData._2, "warning"),
lowData => (lowData.id, "healthy")
)

Union

DataStream → DataStream:对两个或者两个以上的DataStream进行union操作,产生一个包含所有DataStream元素的新DataStream。注意:如果你将一个DataStream跟它自己做union操作,在新的DataStream中,你将看到每一个元素都出现两次。

可以合并多条流,但是数据结构必须一样;

    //合并流union
val unionDStream: DataStream[StartupLog] = appleStream.union(otherdStream)
unionDStream.print("union").setParallelism(1)

Connect与 Union 区别:

1 、 Union之前两个流的类型必须是一样,Connect可以不一样,在之后的coMap中再去调整成为一样的。

2    Connect只能操作两个流,Union可以操作多个

1.2 Sink

Flink没有类似于spark中foreach方法,让用户进行迭代的操作。虽有对外的输出操作都要利用Sink完成。最后通过类似如下方式完成整个任务最终输出操作。

   myDstream.addSink(new MySink(xxxx)) 

官方提供了一部分的框架的sink。除此以外,需要用户自定义实现sink。

 Kafka

object MyKafkaUtil {
val prop = new Properties()
prop.setProperty("bootstrap.servers","hadoop101:9092")
prop.setProperty("group.id","gmall") def getConsumer(topic:String ):FlinkKafkaConsumer011[String]= {
val myKafkaConsumer:FlinkKafkaConsumer011[String] = new FlinkKafkaConsumer011[String](topic, new SimpleStringSchema(), prop)
myKafkaConsumer
} def getProducer(topic:String):FlinkKafkaProducer011[String]={
new FlinkKafkaProducer011[String]("hadoop101:9092",topic,new SimpleStringSchema())
} } //sink到kafka
unionDStream.map(_.toString).addSink(MyKafkaUtil.getProducer("gmall_union"))
///opt/module/kafka/bin/kafka-console-consumer.sh --zookeeper hadoop101:2181 --topic gmall_union
从kafka到kafka

启动kafka

kafka生产者:[kris@hadoop101 kafka]$ bin/kafka-console-producer.sh --broker-list hadoop101: --topic sensor

kafka消费者:

[kris@hadoop101 kafka]$ bin/kafka-console-consumer.sh --bootstrap-server hadoop101: --topic sinkTest --from-beginning
SensorReading(sensor_1,,35.80018327300259)
SensorReading(sensor_6,,15.402984393403084)
SensorReading(sensor_7,,6.720945201171228)
SensorReading(sensor_10,,38.101067604893444)
SensorReading(sensor_1,,35.1)
SensorReading(sensor_1,,35.6)

Redis

import org.apache.flink.streaming.connectors.redis.RedisSink
import org.apache.flink.streaming.connectors.redis.common.config.FlinkJedisPoolConfig
import org.apache.flink.streaming.connectors.redis.common.mapper.{RedisCommand, RedisCommandDescription, RedisMapper} object MyRedisUtil {
private val config: FlinkJedisPoolConfig = new FlinkJedisPoolConfig.Builder().setHost("hadoop101").setPort(6379).build() def getRedisSink(): RedisSink[(String, String)] = {
new RedisSink[(String, String)](config, new MyRedisMapper)
} }
class MyRedisMapper extends RedisMapper[(String, String)]{
//用何种命令进行保存
override def getCommandDescription: RedisCommandDescription = {
new RedisCommandDescription(RedisCommand.HSET, "channel_sum") //hset类型, apple, 111
}
//流中的元素哪部分是value
override def getKeyFromData(channel_sum: (String, String)): String = channel_sum._2
//流中的元素哪部分是key
override def getValueFromData(channel_sum: (String, String)): String = channel_sum._1 } object StartupApp {
def main(args: Array[String]): Unit = {
val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
val myKafkaConsumer: FlinkKafkaConsumer011[String] = MyKafkaUtil.getConsumer("GMALL_STARTUP")
val dstream: DataStream[String] = env.addSource(myKafkaConsumer) //dstream.print().setParallelism(1) 测试从kafka中获得数据是否打通到了flink中 //将json转换成json对象
val startupLogDStream: DataStream[StartupLog] = dstream.map { jsonString =>
JSON.parseObject(jsonString, classOf[StartupLog])
} //sink到redis
//把按渠道的统计值保存到redis中 hash key: channel_sum field ch value: count
//按照不同渠道进行累加
val chCountDStream: DataStream[(String, Int)] = startupLogDStream.map(startuplog => (startuplog.ch, 1)).keyBy(0).sum(1)
//把上述结果String, Int转换成String, String类型
val channelDStream: DataStream[(String, String)] = chCountDStream.map(chCount => (chCount._1, chCount._2.toString))
channelDStream.addSink(MyRedisUtil.getRedisSink())

ES

object MyEsUtil {
val hostList: util.List[HttpHost] = new util.ArrayList[HttpHost]()
hostList.add(new HttpHost("hadoop101", 9200, "http"))
hostList.add(new HttpHost("hadoop102", 9200, "http"))
hostList.add(new HttpHost("hadoop103", 9200, "http")) def getEsSink(indexName: String): ElasticsearchSink[String] = {
//new接口---> 要实现一个方法
val esSinkFunc: ElasticsearchSinkFunction[String] = new ElasticsearchSinkFunction[String] {
override def process(element: String, ctx: RuntimeContext, indexer: RequestIndexer): Unit = {
val jSONObject: JSONObject = JSON.parseObject(element)
val indexRequest: IndexRequest = Requests.indexRequest().index(indexName).`type`("_doc").source(jSONObject)
indexer.add(indexRequest)
}
}
val esSinkBuilder = new ElasticsearchSink.Builder[String](hostList, esSinkFunc)
esSinkBuilder.setBulkFlushMaxActions(10)
val esSink: ElasticsearchSink[String] = esSinkBuilder.build()
esSink
}
} object StartupApp {
def main(args: Array[String]): Unit = {
val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
val myKafkaConsumer: FlinkKafkaConsumer011[String] = MyKafkaUtil.getConsumer("GMALL_STARTUP")
val dstream: DataStream[String] = env.addSource(myKafkaConsumer)
//sink之三 保存到ES
val esSink: ElasticsearchSink[String] = MyEsUtil.getEsSink("gmall_startup")
dstream.addSink(esSink) //dstream来自kafka的数据源
GET gmall_startup/_search

Mysql

class MyjdbcSink(sql: String) extends RichSinkFunction[Array[Any]] {
val driver = "com.mysql.jdbc.Driver"
val url = "jdbc:mysql://hadoop101:3306/gmall?useSSL=false"
val username = "root"
val password = "123456"
val maxActive = "20"
var connection: Connection = null // 创建连接
override def open(parameters: Configuration) {
val properties = new Properties()
properties.put("driverClassName",driver)
properties.put("url",url)
properties.put("username",username)
properties.put("password",password)
properties.put("maxActive",maxActive) val dataSource: DataSource = DruidDataSourceFactory.createDataSource(properties)
connection = dataSource.getConnection()
} // 把每个Array[Any] 作为数据库表的一行记录进行保存 override def invoke(values: Array[Any]): Unit = {
val ps: PreparedStatement = connection.prepareStatement(sql)
for (i <- 0 to values.length-1) {
ps.setObject(i+1, values(i))
}
ps.executeUpdate()
} override def close(): Unit = {
if (connection != null){
connection.close()
}
}
} object StartupApp {
def main(args: Array[String]): Unit = {
val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
val myKafkaConsumer: FlinkKafkaConsumer011[String] = MyKafkaUtil.getConsumer("GMALL_STARTUP")
val dstream: DataStream[String] = env.addSource(myKafkaConsumer) //dstream.print().setParallelism(1) 测试从kafka中获得数据是否打通到了flink中 //将json转换成json对象
val startupLogDStream: DataStream[StartupLog] = dstream.map { jsonString =>
JSON.parseObject(jsonString, classOf[StartupLog])
} //sink之四 保存到Mysql中
startupLogDStream.map(startuplog => Array(startuplog.mid, startuplog.uid, startuplog.ch, startuplog.area,startuplog.ts))
.addSink(new MyjdbcSink("insert into fink_startup values(?,?,?,?,?)")) env.execute() }
}

Fink| API| Time与Window的更多相关文章

  1. NODE-WEBKIT教程(5)NATIVE UI API 之FRAMELESS WINDOW

    node-webkit教程(5)Native UI API 之Frameless window 文/玄魂 原文链接:http://www.xuanhun521.com/Blog/2014/4/15/n ...

  2. node-webkit学习(4)Native UI API 之window

    node-webkit学习(4)Native UI API 之window 文/玄魂 目录 node-webkit学习(4)Native UI API 之window 前言 4.1  window a ...

  3. [虾扯蛋] android界面框架-Window

    从纯sdk及framwork的角度看,android中界面框架相关的类型有:Window,WindowManager,View等.下面就以这几个类为出发点来概览下安卓开发的"界面架构&quo ...

  4. Google 地图 API V3 使用入门

    Google官方教程: Google 地图 API V3 使用入门 Google 地图 API V3 针对移动设备进行开发 Google 地图 API V3 之事件 Google 地图 API V3 ...

  5. 微信内置浏览器的JS API

    /**! * 微信内置浏览器的Javascript API,功能包括: * * 1.分享到微信朋友圈 * 2.分享给微信好友 * 3.分享到腾讯微博 * 4.新的分享接口,包含朋友圈.好友.微博的分享 ...

  6. window.history

    作者:zccst 旧版: forword() backword() go(number) HTML5中新增了 onhashchange  浏览器兼容性较好,用得较多 pushState / repla ...

  7. 了解HTML5和“她”的 API (二)

    Communication(通信)     Cross Document Messaging (跨文档消息通信) postMessage API   origin security(源安全) chat ...

  8. 通过 File API 使用 JavaScript 读取文件

    原文地址:http://www.html5rocks.com/zh/tutorials/file/dndfiles/ 简介 HTML5 终于为我们提供了一种通过 File API 规范与本地文件交互的 ...

  9. HTML5之window.applicationCache对象

    不知道离线缓存技术的可以参照上一篇文章: HTML5之appcache语法理解/HTML5应用程序缓存/manifest缓存文件官方用法翻译 参考文章 window.applicationCache  ...

随机推荐

  1. Linux 的 Crond(二)

    最近由于工作中用到了crond,之前对crond不是很了解,只知道咋用,但是这次需要考虑好多情况,所以又深入了解了一下crond,下面就以下几个问题来谈谈crond. crond 中指定的job,如果 ...

  2. 'index.js' does not match the corresponding name on disk: '.\node_modules\

    跟着视频教程学习react的时候,遇到一个问题,困扰了一阵,最后发现真的很傻! 问题如下: 最后发现是import语句写的有问题,把react写成了React: 正确的引入语句是: import Re ...

  3. 说说 Vue.js 中的 v-cloak 指令

    可以使用 v-cloak 指令设置样式,这些样式会在 Vue 实例编译结束时,从绑定的 HTML 元素上被移除. 当网络较慢,网页还在加载 Vue.js ,而导致 Vue 来不及渲染,这时页面就会显示 ...

  4. 【Linux】文本处理工具介绍

    文本处理工具介绍 grep.sed和awk都是文本处理工具,各自都有各自的优缺点,一种文本处理命令是不能被另一个完全替换的.相比较而言,sed和awk功能更强大,且已独立成一种语言来介绍. grep: ...

  5. jQuery 源码分析(十六) 事件系统模块 底层方法 详解

    jQuery事件系统并没有将事件监听函数直接绑定到DOM元素上,而是基于数据缓存模块来管理监听函数的,事件模块代码有点多,我把它分为了三个部分:分底层方法.实例方法和便捷方法.ready事件来讲,好理 ...

  6. Java设计模式:Abstract Factory(抽象工厂)模式

    概念定义 抽象工厂(Abstract Factory)模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 抽象工厂模式中,系统的产品有多于一个的产品族(一个产品族里定义多个产品) ...

  7. sql server相邻表记录交换(单双两两交换)

    在博客园的博问中看到了一个这样的提问:一个表中有id和name两个字段,id是连续非空不重复的,想要交换相邻表记录的name值(单双两两交换). 另外,如果最后的单独行没有对应的下一行匹配记录的话,就 ...

  8. Oracle - 如何查找指定字符串所出现的表

    需求:举个例子,oracle测试库的scott用户下面的有张emp表,emp表的ename列中有一行数据为'CLARK'.红色标记部分. SQL> select * from scott.emp ...

  9. jvm 性能调优工具之 jstat

    概述 Jstat是JDK自带的一个轻量级小工具.全称“Java Virtual Machine statistics monitoring tool”,它位于java的bin目录下,主要利用JVM内建 ...

  10. ASP.NET MVC AJAX 请求中加入 antiforgerytoken 解决“所需的防伪表单字段“__RequestVerificationToken”不存在”问题

    在ASP.NET mvc中如果在表中使用了@Html.AntiForgeryToken(),ajax post不会请求成功 解决方法是在ajax中加入__RequestVerificationToke ...