前言
开始进入Flink的学习,这里先做一个Flink的入门demo,类似于java里的hello world
一、Flink版WordCount
1.创建Maven项目
创建一个maven项目,导入以下依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.atguigu.flink</groupId>
<artifactId>FlinkTutorial</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-java</artifactId>
<version>1.10.1</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-streaming-java_2.12</artifactId>
<version>1.10.1</version>
</dependency>
</dependencies>
</project>
2.批处理WordCount
DataSet用来进行批处理
代码如下:
//批处理
public class WordCount {
public static void main(String[] args) throws Exception {
//创建执行环境
ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
//从文件读取数据
String inputPath="F:\\IDEA\\Flink\\src\\main\\resources\\hello.txt";
DataSource<String> inputDatsSet = env.readTextFile(inputPath);
DataSet<Tuple2<String, Integer>> resultDS = inputDatsSet.flatMap(new MyFlatMapper()).groupBy(0).sum(1);
resultDS.print();
}
public static class MyFlatMapper implements FlatMapFunction<String, Tuple2<String,Integer>>{
public void flatMap(String value, Collector<Tuple2<String, Integer>> out) throws Exception {
String[] words=value.split(" ");
//遍历所有word,包装成二元组
for(String word:words){
out.collect(new Tuple2<String, Integer>(word,1));
}
}
}
}
整体的思路很清晰,首先创建执行的环境,然后读取文件,再使用flatMap将读取到的一行数据扁平化为元组,再根据key值对元组进行聚合,再对聚合后的元组中的value进行求和。
1)flatMap要求传一个参数:
而FlatMapFunction<T,R>是一个接口,这就要求我们实现这个接口,其中T,O都是泛型,需要我们自己定义:
flatMap这个方法的参数,var1代表我们读取的一条一条的数据,var2是一个收集器,作为输出的结果,所以要实现以下内容:
public static class MyFlatMapper implements FlatMapFunction<String, Tuple2<String,Integer>>{
public void flatMap(String value, Collector<Tuple2<String, Integer>> out) throws Exception {
String[] words=value.split(" ");
//遍历所有word,包装成二元组
for(String word:words){
out.collect(new Tuple2<String, Integer>(word,1));
}
}
}
上面FlatMapFunction<String, Tuple2<String,Integer>>中的String代表这个函数接收到的数据类型,后面的元组类型是想要得到的结果类型(这里使用的是java里的元组类型)
2)groupby
groupby要求传一个参数,代表是按第几个位置进行聚合
3)sum
sum要求传一个参数,代表是按第几个位置进行求和
4)运行结果:
3.流处理WordCount
DataStream进行流处理
代码如下:
public class StreamWordCount {
public static void main(String[] args) throws Exception {
//流处理执行环境
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
//从文件读取数据
String inputPath="F:\\IDEA\\Flink\\src\\main\\resources\\hello.txt";
DataStream<String> inputDatsStream = env.readTextFile(inputPath);
DataStream<Tuple2<String, Integer>> resultDS = inputDatsStream.flatMap(new WordCount.MyFlatMapper()).keyBy(0).sum(1);
resultDS.print();
env.execute();
}
public static class MyFlatMapper implements FlatMapFunction<String, Tuple2<String,Integer>> {
public void flatMap(String value, Collector<Tuple2<String, Integer>> out) throws Exception {
String[] words=value.split(" ");
//遍历所有word,包装成二元组
for(String word:words){
out.collect(new Tuple2<String, Integer>(word,1));
}
}
}
}
这里还是进行了文件读取,实际上最好从端口进行传输数据,更能够看出流处理的特点。
1)keyby
对比于groupby,groupby是对于一批数据进行分组,但是在流处理中,数据是一条一条来的,所以没办法用groupby。
keyby是按key的hashcode对数据进行重分区的操作。
2)打开流处理
相较于批处理,流处理要开启一个开关,然后才开始接收流数据env.execute()
3)运行结果:
跟前面批处理不同的是,批处理只显示了最终结果,而流处理还显示了中间过程。
前面的数字1、8、10等等代表的是并行执行的线程的编号,也可以理解为并行度,当前电脑为16核,所以最高为16。
可以这样设置并行度:env.setParallelism(8);
下面再提供一个从端口接收数据并处理的代码:
public class StreamWordCount {
public static void main(String[] args) throws Exception{
StreamExecutionEnvironment env =
StreamExecutionEnvironment.getExecutionEnvironment();
ParameterTool parameterTool = ParameterTool.fromArgs(args);
String host = parameterTool.get("host");
int port = parameterTool.getInt("port");
DataStream<String> inputDataStream = env.socketTextStream(host, port);
DataStream<Tuple2<String, Integer>> wordCountDataStream = inputDataStream
.flatMap( new WordCount.MyFlatMapper())
.keyBy(0)
.sum(1);
wordCountDataStream.print().setParallelism(1);
env.execute();
}
}
其中,这部分代码可以获取命令行参数:
ParameterTool parameterTool = ParameterTool.fromArgs(args);
String host = parameterTool.get("host");
int port = parameterTool.getInt("port");