关于flink的一些基本介绍这儿就不给大家说了哈,毕竟官网和很多优秀博客都给大家介绍了。此文就给大家介绍flink的批、流代码相关的展示。
flink的入门学习就一定绕不开dataflows的理解,flink dataflows分为source,transformation,sink三大部分。一般来说transformation处会进行大量的逻辑代码操作来达到我们的业务处理目的。source处是接入数据的,没有数据就压根不需要数据处理计算,flink处理的数据都是从source处来的。有数据的输入那么一定就有数据的输出,sink处就是进行数据的输出操作的。我们来看看经典的官网图展示吧。
env:就是flink的计算引擎,此处是flink的流计算引擎
addSource:就是flink的source,接入外部数据输入到flink内部的地方
map,keyBy,timeWindow,apply:都是transformation的一部分,根据具体的业务需求进行数据转化和计算操作
addSink:就是flink的sink,将flink内部计算完成后的结果数据输出到外部储存组件
1 批处理
示例数据
flume,flink,redis
storm,hive,kafka,hbase,phoenix,kafka
hive,phoenix,spark,flume,flink,kafka,kafka,flink
kafka,hive,hive,phoenix
kafka,kafka,kafka,storm,redis,spark
hbase,flume,storm
flume,flink,storm,flume,flume,kafka,spark,phoenix
flink,flink,kafka,hbase
kafka,flink,hive,flink
flume,hbase
hbase,hive
hbase,hbase,flink,phoenix
spark,hbase,flume,spark,hive,spark,flink
hbase,redis,hive
phoenix,storm,storm
flink批处理进行单词计数,此处直接上scala代码
package com.leslie.base.batch
import org.apache.flink.api.scala.ExecutionEnvironment
// scala代码需要该行导入信息,否则在代码写编写过程提示缺失隐式转化信息
import org.apache.flink.api.scala._
/**
* @Author: leslie
* @Description: flink批处理进行word count
* @Time: 2020/1/3 21:42
*/
object WordCount {
def main(args: Array[String]): Unit = {
/*
* 1 flink批处理引擎
* 2 source 读取文件
* 3 transformation 针对每一行数据进行切割处理,在进行单词分组统计
* 4 sink 打印结果
*/
// 获取flink的批处理引擎
val env = ExecutionEnvironment.getExecutionEnvironment
// 读取文件,指定字符编码为utf-8
val originalData: DataSet[String] = env.readTextFile(getPath("words.txt"), charsetName = "UTF-8")
// flatMap算子 读取每一行数据,根据","进行划分成单词数组。再将数组进行压扁操作
val flatData: DataSet[String] = originalData.flatMap(line => line.split(","))
// map算子 将每一个单词和其数量1形成元组 如(flink, 1)
val tupleData: DataSet[(String, Int)] = flatData.map(word => (word, 1))
// groupBy算子 将DataSet根据 元组 的第一个元素"单词"进行分组。参数0代表元组中的第一个元素
val groupedData: GroupedDataSet[(String, Int)] = tupleData.groupBy(0)
// sum算子 将同一分组中 "单词" 进行数量统计。参数1代表元组中的第二个元素
val sinkData: DataSet[(String, Int)] = groupedData.sum(1)
// 打印结果
sinkData.print()
}
// 返回resouce目录中的指定文件路径
def getPath(fileName: String): String = {
this.getClass.getClassLoader.getResource(fileName).getPath // scala默认将最后一行结果返回
}
}
结果输出
(redis,3)
(hive,8)
(flink,10)
(flume,8)
(hbase,9)
(kafka,11)
(storm,6)
(phoenix,6)
(spark,6)
上边flink批处理中进行数据转换和统计操作可以写成一行,但是平时工作的时候不太建议这样操作。在处理逻辑比较复杂的时候,太简洁的代码不利于后边代码维护。能够写成这样简洁是得益于scala语法的特性和语法糖。
env.readTextFile(getPath("words.txt"))
.flatMap(_.split(","))
.map((_, 1))
.groupBy(0)
.sum(1)
.print()
2 流处理
flink流处理进行word count,下边直接给出scala代码
package com.leslie.base.streaming
// scala代码需要该行导入信息,否则在代码写编写过程提示缺失隐式转化信息
import org.apache.flink.api.scala._
import org.apache.flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment}
/**
* @Author: leslie
* @Description: flink流处理进行word count
* @Time: 2020/1/3 23:26
*/
object WordCount {
def main(args: Array[String]): Unit = {
/*
* 1 flink流处理引擎
* 2 source 读取文件
* 3 transformation 针对每一行数据进行切割处理,在进行单词分组统计
* 4 sink 打印结果
*/
// 获取flink流处理引擎
val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
val originalData: DataStream[String] = env.socketTextStream("localhost", 8333)
val sinkData: DataStream[(String, Int)] =
originalData
.flatMap(line => line.split(" "))
.map(word => (word, 1))
.keyBy(0)
.sum(1)
// 打印结果
sinkData.print()
// 流处理需要显式执行
env.execute("flink_streaming_word_count")
}
}
现在用流程描述和截图来展示一下上边flink程序计算结果展示
step1:使用nc命令在本机上的指定端口启动一个服务
step2:启动flink流计算程序
step3:本机nc服务上输入一段字符串,查看计算结果(红框为对应的输入数据,和flink计算结果)
setp4:本机nc服务上再输入一段字符串,查看对应的计算结果
此时是不是发现有些奇怪,明明第二次的数据输入仅有flink spark kafka各一次,为什么计算的结果为(spark,2),(flink,2),(kafka,1)。乍一看好像只有"kafka"次数计算是正确的,为什么会出现这样的结果呢?
原来我们此处并没有指定flink的窗口,所有的计算都是针对所有的数据来进行的,包括之前已经输入的数据。(窗口的概念以后再进行介绍,此处主要只是给大家展示一下flink的流计算)