Flink词频统计实战[Scala版]

文章目录

  • [1. 实战概述](#1. 实战概述)
  • [2. 实战步骤](#2. 实战步骤)
    • [2.1 准备数据文件](#2.1 准备数据文件)
    • [2.2 创建Maven项目](#2.2 创建Maven项目)
    • [2.3 添加项目相关依赖](#2.3 添加项目相关依赖)
    • [2.4 添加Scala SDK](#2.4 添加Scala SDK)
    • [2.5 创建日志属性文件](#2.5 创建日志属性文件)
    • [2.6 创建HDFS配置文件](#2.6 创建HDFS配置文件)
    • [2.7 在源程序目录里创建包](#2.7 在源程序目录里创建包)
    • [2.8 词频统计 - 批处理模式](#2.8 词频统计 - 批处理模式)
      • [2.7.1 创建`BatchWordCount`对象](#2.7.1 创建BatchWordCount对象)
      • [2.7.2 运行程序,查看结果](#2.7.2 运行程序,查看结果)
    • [2.9 词频统计 - 流处理模式](#2.9 词频统计 - 流处理模式)
      • [2.9.1 创建`StreamingWordCount`对象](#2.9.1 创建StreamingWordCount对象)
      • [2.9.2 运行程序,查看结果](#2.9.2 运行程序,查看结果)
    • [2.10 词频统计 - 处理流数据](#2.10 词频统计 - 处理流数据)
      • [2.10.1 利用`nc`产生流数据](#2.10.1 利用nc产生流数据)
      • [2.10.2 启动`nc`监听端口并保持开放](#2.10.2 启动nc监听端口并保持开放)
      • [2.10.3 创建`StreamingDataWordCount`对象](#2.10.3 创建StreamingDataWordCount对象)
      • [2.10.4 启动程序,利用`nc`输入数据,控制台查看结果](#2.10.4 启动程序,利用nc输入数据,控制台查看结果)
      • [2.10.5 退出`nc`,程序结束](#2.10.5 退出nc,程序结束)
  • [3. 实战总结](#3. 实战总结)

1. 实战概述

  • 本实战项目基于 Flink 1.20.5 与 Scala 语言,旨在构建一套完整的词频统计系统。项目涵盖了从 Maven 环境搭建、HDFS 数据准备到代码编写的全过程。核心开发了三种模式的处理程序:基于 BATCH 模式的离线批处理、基于 STREAMING 模式的有界流处理,以及利用 socketTextStream 接入 nc 命令产生的无界数据流进行实时计算。通过对比不同模式下的执行结果,深入理解了 Flink 在批处理与流处理上的统一 API 应用。

2. 实战步骤

2.1 准备数据文件

  1. 创建本地文件

    • 执行命令:vim words.txt
  2. 创建HDFS目录

    • 执行命令:hdfs dfs -mkdir -p /wordcount/input
  3. 上传文件到HDFS

    • 执行命令:hdfs dfs -put words.txt /wordcount/input

2.2 创建Maven项目

  • 配置项目基本信息

  • 单击【Create】按钮,生成项目基本骨架

  • java改成scala

2.3 添加项目相关依赖

  • 在Maven仓库里查看Flink: Streaming Scala的最新版本是1.20.5

  • pom.xml文件里添加6个依赖

    xml 复制代码
    <dependencies>                                                        
        <!-- 1. Flink 核心库 (包含 TextLineInputFormat) -->                    
        <dependency>                                                      
            <groupId>org.apache.flink</groupId>                           
            <artifactId>flink-core</artifactId>                           
            <version>1.20.5</version>                                     
        </dependency>                                                     
        <!-- 2. Flink 流处理 API -->                                         
        <dependency>                                                      
            <groupId>org.apache.flink</groupId>                           
            <artifactId>flink-streaming-scala_2.12</artifactId>           
            <version>1.20.5</version>                                     
        </dependency>                                                     
        <!-- 3. Flink 客户端 (用于本地运行和提交) -->                                 
        <dependency>                                                      
            <groupId>org.apache.flink</groupId>                           
            <artifactId>flink-clients</artifactId>                        
            <version>1.20.5</version>                                     
        </dependency>                                                     
        <!-- 4. 文件连接器 (提供 FileSource) -->                                 
        <dependency>                                                      
            <groupId>org.apache.flink</groupId>                           
            <artifactId>flink-connector-files</artifactId>                
            <version>1.20.5</version>                                     
        </dependency>                                                     
        <!-- 5. Flink Hadoop 兼容包 -->                                      
        <dependency>                                                      
            <groupId>org.apache.flink</groupId>                           
            <artifactId>flink-hadoop-compatibility_2.12</artifactId>      
            <version>1.18.0</version>                                     
        </dependency>                                                     
        <!-- 6. Hadoop 客户端 -->                                            
        <dependency>                                                      
            <groupId>org.apache.hadoop</groupId>                          
            <artifactId>hadoop-client</artifactId>                        
            <version>3.3.4</version>                                      
        </dependency>                                                     
    </dependencies>                                                       
  • 设置源程序目录

  • 刷新项目依赖

2.4 添加Scala SDK

  • 操作录屏演示
  • scala目录里就可以创建Scala类或文件

2.5 创建日志属性文件

  • resources目录里创建log4j.properties文件

    shell 复制代码
    log4j.rootLogger=error, stdout, logfile
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
    log4j.appender.logfile=org.apache.log4j.FileAppender
    log4j.appender.logfile.File=target/flink.log
    log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
    log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n

2.6 创建HDFS配置文件

  • resources目录里创建hdfs-site.xml文件

    xml 复制代码
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        <property>
            <name>dfs.client.use.datanode.hostname</name>
            <value>true</value>
        </property>
    </configuration>
  • 设置 dfs.client.use.datanode.hostname 属性值为 true,用于启用客户端通过 DataNode 主机名(而非 IP)访问 HDFS,常用于集群网络配置或主机名解析场景。

2.7 在源程序目录里创建包

  • 创建net.huawei.flink.wc

2.8 词频统计 - 批处理模式

2.7.1 创建BatchWordCount对象

  • net.huawei.flink.wc包里创建BatchWordCount对象

    scala 复制代码
    package net.huawei.flink.wc
    
    import org.apache.flink.api.common.RuntimeExecutionMode
    import org.apache.flink.streaming.api.scala._
    
    /**
     * 功能:采用批处理模式进行词频统计
     * 作者:华卫
     * 日期:2026年06月20日
     */
    object BatchWordCount {
      def main(args: Array[String]): Unit = {
        // 获取执行环境
        val env = StreamExecutionEnvironment.getExecutionEnvironment
        // 设置为批处理模式
        env.setRuntimeMode(RuntimeExecutionMode.BATCH)
        // 读取 HDFS 文件
        val lines = env.readTextFile("hdfs://master:9000/wordcount/input/words.txt")
        // 词频统计:分词 -> 映射为(word, 1) -> 按单词分组 -> 对计数求和
        val wc = lines
          .flatMap(_.split(" "))
          .map(w => (w, 1))
          .keyBy(_._1)
          .sum(1)
        // 打印结果
        wc.print()
        // 触发执行
        env.execute("Batch Word Count")
      }
    }
  • 代码说明 :本程序基于 Flink Scala API 1.20.5 实现词频统计。通过 StreamExecutionEnvironment 获取执行环境,并设置为 BATCH 批处理模式。从 HDFS 读取文本文件后,依次经过 flatMap 分词、map 映射为 (word, 1) 元组、keyBy 按单词分组、sum 对计数聚合,最终将统计结果打印至控制台。整体流程简洁高效,适用于离线文本分析场景。

2.7.2 运行程序,查看结果

  • 运行BatchWordCount对象

2.9 词频统计 - 流处理模式

2.9.1 创建StreamingWordCount对象

  • net.huawei.flink.wc包里创建StreamingWordCount对象

    scala 复制代码
    package net.huawei.flink.wc
    
    import org.apache.flink.api.common.RuntimeExecutionMode
    import org.apache.flink.streaming.api.scala._
    
    /**
     * 功能:采用流处理模式进行词频统计
     * 作者:华卫
     * 日期:2026年06月20日
     */
    object StreamingWordCount {
        def main(args: Array[String]): Unit = {
          // 获取执行环境
          val env = StreamExecutionEnvironment.getExecutionEnvironment
          // 设置为批处理模式
          env.setRuntimeMode(RuntimeExecutionMode.STREAMING)
          // 设置并行度为2
          env.setParallelism(2);
          // 读取 HDFS 文件
          val lines = env.readTextFile("hdfs://master:9000/wordcount/input/words.txt")
          // 词频统计:分词 -> 映射为(word, 1) -> 按单词分组 -> 对计数求和
          val wc = lines
            .flatMap(_.split(" "))
            .map(w => (w, 1))
            .keyBy(_._1)
            .sum(1)
          // 打印结果
          wc.print()
          // 触发执行
          env.execute("Streaming Word Count")
        }
    }
  • 代码说明 :本程序基于 Flink Scala API 1.20.5 实现流式词频统计。通过 StreamExecutionEnvironment 获取执行环境,设置为 STREAMING 流处理模式,并将并行度设为 2。从 HDFS 读取文本文件后,依次经过 flatMap 分词、map 映射为 (word, 1) 元组、keyBy 按单词分组、sum 增量聚合计数,最终将实时统计结果输出至控制台。适用于持续数据流的实时分析场景。

2.9.2 运行程序,查看结果

  • 运行StreamingWordCount对象
  • 该运行结果展示了 Flink 流处理模式 下的词频统计输出。由于设置了并行度为 2,控制台日志前的数字 1>2> 代表不同子任务(Subtask)的输出线程 ID。结果显示了单词计数的增量更新过程 :例如 (hello,1) 随后变为 (hello,2),表明 Flink 正在实时处理数据流并动态累加计数,而非等待所有数据处理完毕后一次性输出最终结果。这验证了流计算"来一条算一条"的实时特性。

2.10 词频统计 - 处理流数据

2.10.1 利用nc产生流数据

  • 文件充其量只能算有界数据流,如何才能产生无界数据流呢?可以利用Kafka消息队列,当然为了简单起见,我们采用nc来产生流数据。nc是款非常实用的网络工具,它能够建立并接受传输控制协议(TCP)和用户数据报协议(UDP)的连接。小巧而功能强大,被誉为网络安全界的"瑞士军刀"。nc被设计成一个可靠的后端(back-end) 工具,拥有功能丰富的网络调试和开发工具,它可以通过手工或者脚本与应用层的网络应用程序或服务进行交互,可以帮你轻易的建立几乎任何类型的连接,同时还可以当服务器使用,能监听任意指定端口的连接请求,并可做同样的读写操作。
  • 执行命令:nc -h

2.10.2 启动nc监听端口并保持开放

  • 启动nc,监听9999端口,保持开放,可以不断写入数据

2.10.3 创建StreamingDataWordCount对象

  • net.huawei.flink.wc包里创建StreamingDataWordCount对象

    scala 复制代码
    package net.huawei.flink.wc
    
    import org.apache.flink.api.common.RuntimeExecutionMode
    import org.apache.flink.streaming.api.scala._
    
    /**
     * 功能:对流数据进行词频统计
     * 作者:华卫
     * 日期:2026年06月20日
     */
    object StreamingDataWordCount {
      def main(args: Array[String]): Unit = {
        // 获取执行环境
        val env = StreamExecutionEnvironment.getExecutionEnvironment
        // 设置为批处理模式
        env.setRuntimeMode(RuntimeExecutionMode.STREAMING)
        // 设置并行度为2
        env.setParallelism(2)
        // 读取socket文本流数据
        val inputStream = env.socketTextStream("master", 9999)
        // 词频统计:分词 -> 映射为(word, 1) -> 按单词分组 -> 对计数求和
        val wc = inputStream
          .flatMap(_.split(" "))
          .map(w => (w, 1))
          .keyBy(_._1)
          .sum(1)
        // 打印结果
        wc.print()
        // 触发执行
        env.execute("Streaming Data Word Count")
      }
    }
  • 代码说明 :本程序基于 Flink Scala API 1.20.5 实现实时流式词频统计。通过 StreamExecutionEnvironment 获取环境并设置为 STREAMING 模式,并行度设为 2。利用 socketTextStream 监听 master:9999 端口接收数据,核心逻辑依次经过 flatMap 分词、map 映射为 (word, 1)keyBy 按单词分组及 sum 增量聚合计数,最终将实时计算结果打印至控制台,适用于网络数据流的即时分析场景。

2.10.4 启动程序,利用nc输入数据,控制台查看结果

  • 启动StreamingDataWordCount对象,利用nc输入几行数据,在控制台查看词频统计结果
  • 查看nc输入的数据
  • 查看控制台输出的词频统计结果

2.10.5 退出nc,程序结束

  • 切换到nc窗口,按Ctrl + C结束nc进程
  • 此时,程序正常结束

3. 实战总结

  • 本次实战成功实现了基于 Flink Scala API 的词频统计功能,达到了预期的学习目标。首先,在环境配置阶段,通过 Maven 精确引入了 flink-streaming-scalaflink-hadoop-compatibility 等核心依赖,并完成了 Log4j 与 HDFS 的配置,为后续开发奠定了坚实基础。

  • 在代码实现层面,深刻体会到了 Flink 1.20.5 版本中 RuntimeExecutionMode 的灵活性。无论是采用 BATCH 模式一次性输出最终统计结果,还是采用 STREAMING 模式进行增量计算,核心的转换逻辑(flatMapmapkeyBysum)保持高度一致,仅在数据源接入方式和执行模式设置上有所区别。

  • 特别在流处理实战中,通过 nc(Netcat)工具模拟实时数据流,直观地验证了 Flink 的实时计算能力。观察到控制台输出的计数器动态累加过程,验证了流处理"来一条算一条"的低延迟特性。同时,通过对比有界数据流(文件)与无界数据流(Socket)的运行结果,加深了对 Flink 时间语义和窗口机制的初步理解。本次实践不仅掌握了 Flink 程序的基本骨架,更理解了批流统一的编程模型,为后续复杂业务开发积累了宝贵经验。