Flink简单使用

Flink基础入门

本文旨在通过几个小案例来帮助同学们理解Flink的批处理和流处理的简单使用;

项目创建

  • jdk1.8.0_231
  • Apache Maven 3.6.3

相关依赖(来自尚硅谷)

xml 复制代码
<properties>
    <flink.version>1.17.0</flink.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-streaming-java</artifactId>
        <version>${flink.version}</version>
    </dependency>

    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-clients</artifactId>
        <version>${flink.version}</version>
    </dependency>
</dependencies>

有界数据wordCount批处理

思路

  • 环境准备
  • 指定的文件中读取数据
  • 对读取的数据扁平化处理
  • 按照单词进行分组
  • 聚合计算
  • 打印输出

项目准备

在项目目录下创建input目录在目录下创建word.txt文件,内容如下

复制代码
Hello world
Hello bigdata
bigdata good
good KangKing

文件目录结构:

环境准备

java 复制代码
//环境准备,获取当前环境
ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();

文件读取与扁平化处理

java 复制代码
ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
//指定的文件中读取数据
DataSource<String> df = env.readTextFile("D:\\Filnk\\code\\Flink-start\\input\\word.txt");
//对读取的数据扁平化处理
FlatMapOperator<String, Tuple2<String, Long>> FlatMapDS = df.flatMap(
    //定义一个 算子句柄 flatMapDS,它表示"输入是String,输出是 (String, Long) 二元组"的流转换。
        new FlatMapFunction<String, Tuple2<String, Long>>() {
            //FlatMapFunction<IN, OUT> 是 Flink 提供的函数式接口。
            public void flatMap(String s, Collector<Tuple2<String, Long>> collector) throws Exception {
                String[] wordArr = s.split(" ");
                for (String word : wordArr) {
                    //遍历数组,每遇到一个单词就调用 collector.collect(...) 向下游发送一条记录 (word, 1L)
                    collector.collect(Tuple2.of(word, 1L));
                }
            }
        }
);

单词分组与聚合计算

java 复制代码
    //按照单词进行分组
    UnsortedGrouping<Tuple2<String, Long>> groupByDS = FlatMapDS.groupBy(0);//按照元组的第一个元素分组
    //将元组中的第二个元素聚合
    AggregateOperator<Tuple2<String, Long>> sumDS = groupByDS.sum(1);

输出

java 复制代码
//输出
try {
    sumDS.print();
} catch (Exception e) {
    throw new RuntimeException(e);
}

有界数据wordCount流处理

思路

  • 环境准备
  • 指定的文件中读取数据
  • 对读取的数据扁平化处理
  • 按照单词进行分组
  • 聚合计算
  • 打印输出

环境准备与读取数据

java 复制代码
//环境准备
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
//指定文件读取数据
DataStreamSource<String> ds = env.readTextFile("D:\\Filnk\\code\\Flink-start\\input\\word.txt");
env.setRuntimeMode(RuntimeExecutionMode.AUTOMATIC);//设置运行模式,下面作详细解释

这里环境的获取函数变成了Stream流处理开头;

数据处理

java 复制代码
//扁平化处理
SingleOutputStreamOperator<Tuple2<String, Long>> flatMap = ds.flatMap(
        new FlatMapFunction<String, Tuple2<String, Long>>() {
            public void flatMap(String s, Collector<Tuple2<String, Long>> collector) throws Exception {
                String[] wordArr = s.split(" ");
                for (String word : wordArr) {
                    collector.collect(Tuple2.of(word, 1L));
                }
            }
        }
);

这里的逻辑同上面一样,这里不过多赘述

java 复制代码
//按照按照二元组的第一个元素进行分组(keyBy)
KeyedStream<Tuple2<String, Long>, Tuple> keyDS = flatMap.keyBy(0);
//聚合计算
SingleOutputStreamOperator<Tuple2<String, Long>> sum = keyDS.sum(1);
//打印输出
sum.print();
//显示提交(env.excute())
try {
    env.execute();//显示配置
} catch (Exception e) {
    throw new RuntimeException(e);
}

这里的分组操作与批处理的不同,批处理调用的是FlatMapDS.groupBy(0);

这里调用的是keyBy(0)但是这里的原理是相同的

要注意的是这里要配置显示输出,执行print才会有输出

设置运行环境

java 复制代码
env.setRuntimeMode(RuntimeExecutionMode.AUTOMATIC);//配置运行模式

在这里我们看到有三种参数

java 复制代码
STREAMING,
BATCH,
AUTOMATIC;

在没有配置上面的信息的时候,他默认是流处理;输出结果如下

我们可以看到他是逐步的读取信息,遇见已有的key就作累加操作,这里就很有流式处理的味道了

在配置了RuntimeExecutionMode.AUTOMATIC之后的输出如下

我们可以直接看到输出结果,而没有操作的过程,这很显然这是一个批处理操作

所以在配置了AUTO选项以后在运行程序的时候他就会先检测这个数据源是有界的还是无界的,

有界数据,例如文本文件,数据库,采用批处理技术;无界(端口输出的日志文件):采用流处理;

无界数据流式处理

流程

  1. 环境准备
  2. 从指定的网络端口读取数据
  3. 对读取的数据扁平化处理,封装为二元数组,向下传递
  4. 按照单词进行分组
  5. 求和计算
  6. 打印输出
  7. 提交作业
java 复制代码
public static void main(String[] args) throws Exception {
//流处理的环境准备
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStreamSource<String> socketDS = env.socketTextStream("192.168.47.142", 8888);//指定数据源
SingleOutputStreamOperator<Tuple2<String, Long>> flatMap = socketDS.flatMap(
        new FlatMapFunction<String, Tuple2<String, Long>>() {
            public void flatMap(String s, Collector<Tuple2<String, Long>> collector) throws Exception {
                String[] wordArr = s.split(" ");
                for (String word:wordArr) {
                    collector.collect(Tuple2.of(word, 1L));
                }
            }
        }
);
//分组操作(复杂写法)
KeyedStream<Tuple2<String, Long>, String> keyBy = flatMap.keyBy(
        new KeySelector<Tuple2<String, Long>, String>() {
            public String getKey(Tuple2<String, Long> stringLongTuple2) throws Exception {
                return stringLongTuple2.f0;
            }
        }
);
//KeyedStream<Tuple2<String, Long>, String> keyBy = flatMap.keyBy(0)//简单写法
SingleOutputStreamOperator<Tuple2<String, Long>> sum = keyBy.sum(1);
sum.print();
env.execute();

这里的分组操作有两种

​ 有针对复杂情景的自定义句柄的写法,这里也可以使用简单方法,剩下的不过多赘述

​ 启动程序后,在对应的虚拟机的端口启动我们的输出

shell 复制代码
[root@kangking ~]# nc -lk 8888
hello
world
hello

这里我们可以看到实时的输出,这里我们可以看到具体的过程,这就是"支持状态计算",非常有趣;

注意

我们在写FlatMap里面的匿名内部类的时候,显示new FlatMapFunction<String, Tuple2<String, Long>>() 是灰色的,因为IDEA推荐我们使用Lambda表达式

java 复制代码
flatMap = socketDS.flatMap(
        (FlatMapFunction<String, Tuple2<String, Long>>) (s, collector) -> {
            String[] wordArr = s.split(" ");
            for (String word:wordArr) {
                collector.collect(Tuple2.of(word, 1L));
            }
        }
).returns(Types.TUPLE(Types.STRING, Types.LONG));

如上,点击运行

shell 复制代码
Exception in thread "main" org.apache.flink.api.common.functions.InvalidTypesException: The return type of function 'main(Flink_UnBound_Stream.java:19)' could not be determined automatically, due to type erasure. You can give type information hints by using the returns(...) method on the result of the transformation call, or by letting your function implement the 'ResultTypeQueryable' interface.
at org.apache.flink.api.dag.Transformation.getOutputType(Transformation.java:543)

报了一个错误,因为java在使用Lambda表达式的时候容易丢掉他的返回类型,造成了返回类型的缺失,我们需要显示的声明一下他的返回类型

java 复制代码
flatMap = socketDS.flatMap(
    (FlatMapFunction<String, Tuple2<String, Long>>) (s, collector) -> {
        String[] wordArr = s.split(" ");
        for (String word:wordArr) {
            collector.collect(Tuple2.of(word, 1L));
        }
    }
).returns(Types.TUPLE(Types.STRING, Types.LONG));//声明返回类型

接下来就成功运行了;

相关推荐
petrel20152 小时前
【Spark 核心内参】2025.10:从 Parquet 谓词下推的“度”到语义建模的“野心”
大数据·spark
TDengine (老段)2 小时前
TDengine ODBC 连接器进阶指南
大数据·数据库·物联网·时序数据库·tdengine·涛思数据
2501_941982052 小时前
企微API自动化:动态权重分配新策略
大数据
ViiTor_AI2 小时前
Instagram 视频如何转文字并翻译成多语言?AI 字幕与本地化实战指南
大数据·人工智能
物联网软硬件开发-轨物科技3 小时前
【轨物方案】新能源的下半场:构筑光伏场站全生命周期智慧运维新范式
大数据·人工智能·物联网
汇智信科11 小时前
智慧矿山和工业大数据解决方案“智能设备管理系统”
大数据·人工智能·工业大数据·智能矿山·汇智信科·智能设备管理系统
阿里云大数据AI技术12 小时前
Hologres Dynamic Table 在淘天价格力的业务实践
大数据·人工智能·阿里云·hologres·增量刷新
OpenCSG15 小时前
新能源汽车行业经典案例 — 某新能源汽车 × OpenCSG
大数据·人工智能·汽车·客户案例·opencsg
外参财观15 小时前
流量变现的边界:携程金融按下暂停键后的冷思考
大数据·人工智能·金融