news 2026/10/14 14:15:03

Hadoop词频统计完整实战:从环境搭建到避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Hadoop词频统计完整实战:从环境搭建到避坑指南

简介:一套面向Hadoop初学者的词频统计完整实现包,基于Hadoop2.2.0,有效解决入门者缺少可运行范例、难以直观理解MapReduce分布式计算流程的问题。包体共17个文件,包含7个Java源码、7个编译后的class文件、1个约十万单词的TXT测试文件,以及Eclipse工程的.project与.classpath配置,整体仅154KB,轻量且便于直接导入工程运行。压缩包采用zip格式,解压后源码与class文件分目录存放,便于对照学习。该资源已有5865人学习下载,是Hadoop词频统计经典案例中较受关注的参考实现。借助这套文件,读者可以获取从Mapper、Reducer到作业提交的完整可编译代码,利用自带测试文件验证词频输出,并通过对照源码与class文件辅助理解编译部署细节,直观感受Map、Shuffle、Reduce阶段的协作过程,适合课程实验、自学入门、技术面试准备或二次开发模板使用。

1. Hadoop 词频统计在跑什么:一条命令背后的一整套分布式作业

标题写着「Hadoop 词频统计(完整版)」,它不是一个需要费力解释的新技术,而是一条把 HDFS、MapReduce、YARN 串起来的最小闭环。你在这道题里做的每一件事——建目录、传文件、写 Mapper、打包、执行 hadoop jar 提交、看运行日志——都直接对应一次真实的分布式作业链路。反直觉的地方在于:代码五分钟能写完,环境却可能卡你三天,而最容易让人翻车的不是算法,是那些没人明说的小前提。

这个方向适合三类人。刚把 Hadoop 装完、还不知道下一步该干什么的初学者;课程设计要交一个能现场演示的项目、不想只截图的在校生;准备面试、想亲手把 WordCount 从头跑到尾的求职者。它不能让你立刻上手生产集群,但能让你在提交作业之前,先对「数据在哪、计算在哪、日志在哪」有清晰的认知。

一句话把目标说透:用 MapReduce 统计一批文本里每个词的出现次数,输入从 HDFS 读,结果写回 HDFS,中间所有 shuffle 和归并不落本地磁盘。这个闭环一旦跑通,后续再学分区、排序、Combiner、合并去重,都是往这条链路上加零件。

2. 准备一个能跑词频的 Hadoop:伪分布式是性价比最高的起点

2.1 先分清三种部署模式:伪分布式不是低配,是单机调试的最优解

Hadoop 的部署模式按「进程是否分开、数据是否走 HDFS」分成三种,常见做法是单机模式、伪分布式、完全分布式,选型直接决定你接下来的排查路径。

单机(本地)模式下,MapReduce 跑在本地文件系统上,不需要启动 NameNode 和 DataNode,也不经过 YARN。用它调 Mapper 的小逻辑可以,但跑出来的作业根本看不到分布式链路,很多装完 Hadoop 的同学被「hadoop jar 报错找不到 HDFS」卡住,就是因为还在单机模式里。完全分布式则至少要三台机器,要处理免密登录、节点间时间同步、多份配置分发,词频统计的代码本身不复杂,把时间耗在集群铺底上不划算。

伪分布式是中间那条性价比最高的路:所有 NameNode、DataNode、ResourceManager、NodeManager 进程都在一台机器上,但数据通路和作业调度流程与真实集群一致。我一般建议第一遍词频统计就在伪分布式上做,而且在 Ubuntu 虚拟机或裸机里做,而不是直接在 Windows 上用 IDEA 调试。Windows 下用 IDEA 搭 Hadoop 开发环境并不是不行,问题是本地文件系统权限模型和 HDFS 不一致,还常缺 winutils.exe 的可执行权限,很多人在这上面耗掉半天。先用 Linux 把通路跑通,再回到 IDEA 里做编码调试,是更稳的路径。想省掉系统依赖,也可以直接用 Hadoop 的 Docker 镜像,效果接近,前提是你对容器目录挂载不陌生。

2.2 从零装一个伪分布式:JDK、SSH、四个配置文件和一次格式化

伪分布式的安装步骤看起来长,实际就三件事:让 Hadoop 能找到 JVM、让 SSH 能免密连本机、让四个 XML 配置指向正确参数。下面步骤以 Hadoop 3.x 在 Ubuntu 上的做法为例,路径按你实际解压位置改。

先装 JDK 8 或更高版本,解压 Hadoop 到 /opt/hadoop,然后追加环境变量。Hadoop 3.x 要求 JDK 8 以上,我自己常用 JDK 8,最稳,内存占用也小。

# /etc/profile 追加以下内容,Java 路径改成你自己的实际路径 export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 export HADOOP_HOME=/opt/hadoop export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin source /etc/profile java -version # 确认 JDK 可用 hadoop version # 确认 Hadoop 命令可用

然后配置 SSH 免密。伪分布式下,NameNode 要用 SSH 拉起本机的 DataNode 和 SecondaryNameNode,没有免密会一直在启动时让你输密码,脚本直接挂起。

ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys ssh localhost

ssh localhost 能直接登录、不要求输入密码,这一步就算过了。接下来是核心配置文件,共四个。先说一个总开关:core-site.xml 里的 fs.defaultFS 定义了整个集群的默认文件系统,必须写成 hdfs://localhost:9000,这样后续所有相对路径才走 HDFS;如果漏配,hadoop jar 提交的词频作业会把输入输出都当成本地路径,直接报 Input path does not exist,这个错误在第 5 章还会再见到。

hdfs-site.xml 里三个参数值得注意。dfs.replication 在伪分布式下必须设为 1,因为只有一个 DataNode 节点,副本数设成默认的 3 会导致块一直处于 under-replicated 状态,fsck 不断告警。dfs.namenode.name.dir 和 dfs.datanode.data.dir 建议指到 /opt/hadoop/data 下的独立目录,不要用默认的 /tmp/hadoop-*。系统重启会清掉 /tmp,NameNode 的元数据也没了,下次启动先报文件不存在,再报 clusterID 不匹配,属于最典型的翻车现场。

mapred-site.xml 在 3.x 里一开始只有 mapred-site.xml.template,需要自己复制一份,配置里只需一句话:mapreduce.framework.name 设为 yarn,表示作业交给 YARN 调度。保持默认 local 的话,作业会在本地跑,你依然看不到 ResourceManager 上的任务链路。

yarn-site.xml 里两个关键参数:yarn.nodemanager.aux-services 必须写成 mapreduce_shuffle,这是 NodeManager 为 MapReduce 的 shuffle 阶段开的辅助服务,漏配的话作业会一直停在 0% 不前进;yarn.nodemanager.resource.memory-mb 按物理内存调整,单机 8G 内存的机器我一般给 4096,给太少容器会被快速杀,给太多会和操作系统争内存。

注意:hdfs namenode -format 只需要在第一次启动前执行一次,重复格式化会让 NameNode 生成新 clusterID,与 DataNode 里已有的一致不上,启动日志会出现两个 clusterID 的报错。

hdfs namenode -format $HADOOP_HOME/sbin/start-dfs.sh $HADOOP_HOME/sbin/start-yarn.sh

2.3 验证进程与数据通道:jps 缺哪个进程,先查哪个日志

启动完先不要急着写代码,用 jps 看进程是否齐全。这个命令输出的五条记录分别对应 HDFS 和 YARN 的核心角色,缺哪一个,后面的词频统计都会以奇怪的方式失败。

进程名职责
NameNode管理文件系统的命名空间和块元数据
DataNode实际存储数据块,响应读写请求
SecondaryNameNode定期合并 NameNode 的编辑日志,不是热备
ResourceManager接受作业提交,分配容器
NodeManager启动和监控容器,执行任务

如果进程有缺失,去 $HADOOP_HOME/logs 下看对应日志,通常是配置路径不存在或权限不对。进程都齐了之后,用 HDFS 命令确认数据通道可用:

hdfs dfsadmin -report # 看 DataNode 是否在线,容量是否正常 hdfs dfs -ls / # 能列出根目录,说明 HDFS 读写链路通了

到这里,伪分布式环境就绪。之后在 Windows 上用 IDEA 搭 Hadoop 开发环境时,也建议先用这套 Linux 环境把 HDFS 路径传熟,编码调试可以两边切换着来,不用死磕一个环境。

3. 把文本送进 HDFS:输入数据的三种准备方式和路径选择

3.1 本地文件与 HDFS 是两套文件系统:上传和路径是词频统计的第一个坑

很多人写完代码第一次提交就报 Input path does not exist,查看错误信息发现路径是 file:/home/user/xxx,而不是 hdfs://localhost:9000/xxx。本质原因是:伪分布式下,你跑命令的 shell 看到的文件系统是 Linux 本地,而 MapReduce 作业从 HDFS 读数据,两边互不相通。文本必须先用 hdfs dfs -put 上传到 HDFS 的某个目录,再把那个目录路径传给作业。

这里有个容易混淆的点:hadoop fs 和 hdfs dfs 两个命令在 3.x 里基本等价,都是操作 HDFS 的入口。我习惯用 hdfs dfs,因为它更明确表达操作对象。上传之前先规划目录,常见做法是建一个 /wordcount 目录,下面分 input 和 output 两个子目录。输出目录不要提前创建,MapReduce 会自己建,而且要求它必须不存在,否则提交时直接报错。

3.2 上传与校验:mkdir、put、fsck 三个命令一次做完

给一组能直接抄的命令。假设文本在本地 /home/user/input/words.txt。

hdfs dfs -mkdir -p /wordcount/input hdfs dfs -put /home/user/input/words.txt /wordcount/input/ hdfs dfs -ls -R /wordcount hdfs dfs -stat "%b %n" /wordcount/input/words.txt hdfs fsck /wordcount/input/words.txt -files -blocks

mkdir -p 会递归创建目录,目录不存在时不会报错;put 把本地文件复制进 HDFS,原文件保留;ls -R 确认文件已就位并看大小;stat 里的 %b 是文件字节数,%n 是文件名,用来确认文件完整;fsck 查看文件被切成几个块、副本数是否满足配置。对小文件来说,这里能看到它只有一个块、一个副本,这就自然引出小文件问题。

词频统计的输入通常只有几 MB,而 HDFS 默认块大小是 128MB。每个文件会占用一个 InputSplit,也就是说即使文件只有 1KB,MapReduce 也会为它启动一个完整的 Map 任务,启动开销远大于处理本身。目录里如果放了 100 个小文件,就会启动 100 个 Map 任务,伪分布式下单机资源很快被打满,作业表现为「卡住」。常见做法是把多个小文件先合并成一个文本再上传,或者直接在 HDFS 上用 hadoop fs -put 一次传一个较大的文件。先记住结论:词频统计的输入文件宁少勿多,一个输入目录下一个大文件是最省事的形态。

3.3 中文文本的三道关口:编码、BOM 与换行符

词频统计的素材里中文很常见,课程设计几乎都逃不掉。Hadoop 的 TextInputFormat 默认按行读取,字节流解码用作业运行环境的默认编码,最稳妥的是 UTF-8 无 BOM。三个典型案例我都在不同机器上遇到过。

第一,文件是 GBK 编码,输出里中文全变问号或乱码。解决方法是先确认编码,再转码。第二,文件是 UTF-8 但带 BOM。BOM 是文件开头的三个不可见字节,解码后第一个词会被拼上一个 \ufeff 前缀,统计结果里出现一个带着隐形字符的「脏词」,从显示上几乎看不出来,只能靠排序对比发现多了一个词。第三,文件从 Windows 复制过来,换行是 CRLF,单词末尾会带着 \r,同一个词在输出里出现两种形态:一个带 \r,一个不带,词频被拆开。

准备文本时用下面这三条命令做一次预处理,之后不用再排查编码问题:

file -i words.txt # 查看实际编码 iconv -f GBK -t UTF-8 words.txt > words_utf8.txt # 如果确认是 GBK 就转码 sed -i 's/\r$//' words_utf8.txt # 去掉行尾的 CR 字符

转码后建议再用 file -i 确认一次输出。这三道关口处理完,中文文本进入 HDFS 才没有后续隐患。编码问题在词频统计里表现成「乱码」,在稍大的作业里会演化成排序错乱或者 reduce 阶段数据处理异常,前置处理比事后排查省时间。

4. 编写词频统计的 MapReduce:Mapper、Reducer 与驱动类的完整实现

4.1 先把三阶段分工讲清:WordCount 为什么是面试常客

词频统计的经典实现是每行文本按分隔符切词,每个词输出一条<词, 1>,shuffle 阶段 Hadoop 自动按词分组,同一个词的所有 1 汇到同一个 Reducer,Reducer 求和。整个计算被拆成三个阶段:Map 负责并行切词,Shuffle 负责合并同类项,Reduce 负责归并计数。

这里有一个面试里必考的点:Combiner 为什么能放在 Mapper 之后。Combiner 是在 Map 输出端做的本地预聚合,因为「求和」满足交换律和结合律,先在本机把同一个词的计数加一次,再传给 Reducer,网络传输量大大减少。词频统计是 Combiner 的最佳示范,它能让你直观看到加了 Combiner 之后,job 的 counter 里 map 输出记录数明显下降。这正是 hadoop 面试题里常问的 shuffle 过程在真实作业里的体现。

关于 Mapper 输入输出的类型设计,锁定为 LongWritable -> Text -> Text -> IntWritable。行偏移量当 key,行文本当 value;输出时反过来,词当 key,固定的 1 当 value。类型定错会在 reduce 端反序列化时直接抛异常,这是新手最常见的运行时错误。

4.2 Mapper 和 Reducer 代码:一个处理切词,一个处理求和

下方是 Mapper 的完整实现,注意切词的正则我写了注释说明。用 \W+ 切英文天然合适,加了中文就翻车,因为 \W 会把中文字符也当成分隔符,一整行中文会被切没。想要统计中文,一般用 \s+ 按空白切,或者先做分词再喂给 MapReduce。

import java.io.IOException; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Mapper; public class TokenizerMapper extends Mapper<LongWritable, Text, Text, IntWritable> { private final static IntWritable one = new IntWritable(1); private Text word = new Text(); @Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { // 英文文本用 \W+ 切分,只保留字母和数字 // 含中文的文本建议改成 split("\\s+"),否则中文会被当成分隔符 String[] tokens = value.toString().split("\\W+"); for (String token : tokens) { if (token.length() > 0) { word.set(token); context.write(word, one); } } } }

Reducer 的代码更短,它收到的 values 是这个词在 shuffle 之后汇集的全部 1,直接累加即可:

import java.io.IOException; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Reducer; public class IntSumReducer extends Reducer<Text, IntWritable, Text, IntWritable> { private IntWritable result = new IntWritable(); @Override protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException { int sum = 0; for (IntWritable val : values) { sum += val.get(); } result.set(sum); context.write(key, result); } }

两个类都不需要维护状态,也不用考虑线程,这是 MapReduce 最容易理解的地方。唯一的边界条件是:values 是 Iterable 不是 List,如果需要多次遍历,必须先 copy 到本地集合,否则第二次遍历拿到的是空集。比如想先求总数再算占比,就会发现自己遍历第二次拿不到数据。

4.3 驱动类:五个必设参数和两个减配选项

驱动类把上面两个类拼装成一个 Job。五个必设参数分别是 setJarByClass、setMapperClass、setCombinerClass、setReducerClass、输出 key/value 类型。少了任何一个,作业都能提交,但行为会和预期不同:不设 setJarByClass,远程节点找不到用户类;不设输出类型,默认是 LongWritable 和 Text,reduce 输出类型不一致时序列化直接报错。

import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Job; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class WordCount { public static void main(String[] args) throws Exception { if (args.length != 2) { System.err.println("Usage: WordCount <input> <output>"); System.exit(2); } Configuration conf = new Configuration(); Job job = Job.getInstance(conf, "word count"); job.setJarByClass(WordCount.class); job.setMapperClass(TokenizerMapper.class); // 中文文本统计时 Combiner 仍然适用,因为加法满足结合律 job.setCombinerClass(IntSumReducer.class); job.setReducerClass(IntSumReducer.class); job.setOutputKeyClass(Text.class); job.setOutputValueClass(IntWritable.class); FileInputFormat.addInputPath(job, new Path(args[0])); FileOutputFormat.setOutputPath(job, new Path(args[1])); System.exit(job.waitForCompletion(true) ? 0 : 1); } }

注意:输出目录不能提前存在。Hadoop 在作业启动时会检查输出路径,已存在的目录会直接触发 FileAlreadyExistsException。

两个减配选项也值得知道。如果只想验证 Mapper 到输出的过程,可以调用 setNumReduceTasks(0),作业会跳过 reduce,直接输出 map 的结果,这在排查「为什么输出为空」时非常有用。另一个是压缩相关配置,测试阶段不要开启输出压缩,否则 part 文件是 .gz 后缀,直接 cat 全是乱码,影响人工判断。

4.4 编译打包与提交:hadoop classpath 和 hadoop jar 的意义

代码写在三个文件里,编译前先确认环境里能找到 Hadoop 的类库。hadoop classpath 命令会把所有依赖 Jar 一次性拼出来,避免编译期缺包,这比手动去 lib 目录逐个找快得多。Eclipse 里配置 Hadoop 项目也是这个套路,把 $(hadoop classpath) 的输出配到项目 classpath 即可。

mkdir -p /home/user/wordcount/classes cd /home/user/wordcount javac -encoding UTF-8 -classpath $(hadoop classpath) -d classes \ TokenizerMapper.java IntSumReducer.java WordCount.java jar -cvf wordcount.jar -C classes . hadoop jar wordcount.jar WordCount /wordcount/input /wordcount/output/wc001

javac 的 -encoding UTF-8 是专门为中文源码准备的,不加的话编译器在中文注释和字符串上可能出现编码警告。hadoop jar 的第一个参数是 Jar 包,第二个是主类名,后面依次是输入目录和输出目录。注意这里传的是 HDFS 路径,不要再加 file:// 前缀,否则又会绕回第 3 章说过的本地路径问题。

提交之后终端会逐行打印 map 和 reduce 的进度百分比。看到两个进度都到 100%、出现 Job completed successfully,接着用 hdfs dfs -cat /wordcount/output/wc001/part-r-00000 查看结果。如果你是在 Windows 下用 IDEA 搭 Hadoop 开发环境,可以在本地用 Configuration 加载四个 XML 配置调试,但提交到伪分布式集群仍然建议用 Linux 命令行,不要试图把 IDEA 的本地提交和远程集群调度混在一起。

5. 词频统计避坑:5 条真实翻车记录与排查顺序

5.1 现象:作业提交后一直 Running job,进度停在 0%

这是伪分布式里最常见的问题,几乎每个初学者都遇到过。hadoop jar 提交后,日志停在 Running job,等十分钟还是 0%,不是数据量大,是任务根本没被调度。

原因有两种。第一种是 YARN 没真正起来,可能 start-yarn.sh 忘了执行,或者 ResourceManager 进程被系统杀掉;第二种是 yarn-site.xml 的 aux-services 漏配,NodeManager 不知道要为 shuffle 开辅助服务,Map 阶段完成后 Reduce 无法拉数据,整个作业僵在那里。

解决按顺序排查:先 jps 看有没有 ResourceManager 和 NodeManager;再执行 yarn node -list -all 看节点状态;没反应就去 $HADOOP_HOME/logs/yarn-*.log 看 ResourceManager 的启动日志;确认进程都在后,检查 yarn-site.xml 里 aux-services 是否写了 mapreduce_shuffle。这四步走完,绝大多数「永远 Running」都能定位,不用重启机器,也别靠玄学。

5.2 现象:作业秒完,输出目录里只有 _SUCCESS,没有词频结果

作业状态显示成功,但 part-r-00000 是空的,或者文件里只有几行,和预期差很远。这种「黑匣子式」的成功最让人头疼,因为它不报错。

原因通常是两类:输入目录是空的,或路径名写错指到一个不存在的目录;Mapper 里切词后所有 token 都为空,最常见是用了 \W+ 处理全中文文本。这两类在日志里看 counter 就能发现:map input records 是 0,或者 mapper output records 是 0。还有一种属于作业直接失败,日志里出现 InputMismatchException,那就要查 Mapper 和 Reducer 的泛型是否匹配,常见是输出 key/value 类型写反。

排查时我一般会在驱动类里临时加 setNumReduceTasks(0),重跑一次看 map 的中间结果。有产出就说明 map 正常、问题在 reduce;map 输出是 0,问题在切词或输入路径。定位后把临时代码改回去。这条排查路径比一行行读源码高效得多。

5.3 现象:中文统计结果全乱码,或第一个词前面带着隐形字符

输入准备和代码都对,结果里的中文却变成问号,或者排序后第一个词看起来空白但实际存在。这类问题的根源都在编码链路:文件编码、编译编码、运行编码三处必须统一成 UTF-8。

文件侧的处理在第 3 章已经给过 iconv 命令;编译侧用 javac -encoding UTF-8;运行侧在 hadoop jar 前设置 HADOOP_OPTS。三步做完,中文乱码基本不会出现。BOM 导致的隐形前缀词单独说明:把输出用 hdfs dfs -cat 导出来,在 Linux 上用 sed -n l 查看第一个词的不可见字符,如果看到 \ufeff,说明输入文件带 BOM,去掉 BOM 后重跑。

export HADOOP_OPTS="-Dfile.encoding=UTF-8" hadoop jar wordcount.jar WordCount /wordcount/input /wordcount/output/wc001

5.4 现象:本地用 IDE 跑通了,命令行提交却报 Input path does not exist

在 Windows 下用 IDEA 搭 Hadoop 开发环境的人最容易遇到这个割裂:代码在本地调试能出结果,换成 hadoop jar 提交,报错路径不存在。

原因很直接:IDEA 里 Configuration 默认使用本地文件系统,你给的路径被解析成 file:/ 开头;而伪分布式集群要求 hdfs:// 开头的路径。解决方法是提交前确认路径、上传、再提交三步走:hdfs dfs -ls /wordcount/input 看文件在不在;不在就先 put;然后传给 WordCount 的两个参数写 HDFS 路径。同一个作业,IDE 里跑通只说明代码逻辑正确,不代表数据到了 HDFS,这是两个环境,排错时别混着看。

5.5 现象:容器被 ApplicationMaster 反复 kill,日志说超出物理内存

作业一开始跑就报 Container killed by the ApplicationMaster,或者 running beyond physical memory limits,尤其容易出现在单机内存不大、又同时跑多个 Map 任务的伪分布式上。

原因是默认参数和物理机内存不匹配。YARN 默认按节点资源调度,单机 8G 内存跑一个作业,mapreduce.map.memory.mb 默认 1024MB,Map 任务多了以后,叠加系统开销很容易触顶。解决思路是调小 YARN 的资源预算而不是加内存:yarn.nodemanager.resource.memory-mb 设为物理内存的一半左右,yarn.scheduler.maximum-allocation-mb 同步调小,mapreduce.map.java.opts 的 -Xmx 控制在 768m 以内。注意调参数是止血,真正的长期方案是上完全分布式,或者换更大内存的机器。

6. 从「跑通」到「跑对」:用英文文本验证正确性,再拿中文文本做边界测试

6.1 用已知答案的文本做回归

作业跑通后第一件事不是看结果,是验证结果对不对。我会准备一份只有三个词的小文本,比如 a b a c b a,期望输出是 a 3、b 2、c 1。跑完用命令对比:

echo "a b a c b a" | tr ' ' '\n' | LC_ALL=C sort | uniq -c hdfs dfs -cat /wordcount/output/wc001/part-r-00000

两侧结果一致,作业才算真跑通。对比时注意把本地排序的语言环境固定为 C,否则 sort 的排序规则和 Hadoop 的 Text 字节序不一致,会误判为结果错误。

6.2 下一步值得做的两个方向:合并去重和资源调度观察

跑通后想进阶,最自然的延伸是改 Mapper 的输出 key。把「词频统计」改成「合并去重」只需要换 Reducer 逻辑:统计时对 value 求和,去重时直接输出 key,一条链路上换一段代码得到两种结果,这正是 hadoop 课程里常用的一题多改。另一个方向是去对比 Spark 和 Flink 各自版本的 wordcount,理解同样的 Map-Reduce 思想在内存计算框架下为什么有不同表现,但 Hadoop 这一版的核心价值在于把 HDFS、MapReduce、YARN 的完整链路走一遍,这个体验不可替代。

作业提交到 YARN 的流程也可以通过 Web 界面观察:默认 8088 端口打开 ResourceManager 页面,能看到 Application 的状态从 ACCEPTED 到 RUNNING 再到 FINISHED 的完整转换。把这个过程截下来,课程设计答辩时比贴代码更有说服力。

我自己养成的习惯是:每次作业结束,先看 _SUCCESS 是否存在,再看 counter 里 map input records 与 reduce output records 是否对得上,最后才打开结果文件。三个点确认完,才敢说这个作业是真的完成了。这套验证习惯沿用到现在,希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 14:14:47

哈希算法:一根看不见的 “指纹“,如何撑起整个互联网

引子&#xff1a;你每天都在用它&#xff0c;却未必说得清它先看四件毫不相干的事。你在官网下载软件&#xff0c;页面角落挂着一串 64 位英数字符&#xff0c;你从没点开看过。 你注册某个 App&#xff0c;服务器转身就把密码变成一串乱码存进数据库&#xff0c;没人再记得你的…

作者头像 李华
网站建设 2026/10/14 14:14:33

zh-core-web-lg离线前端包:中文原生、信创适配、内网零依赖

简介&#xff1a;本资源为spaCy中文语言模型zh_core_web_lg-3.8.0的完整离线安装包&#xff0c;面向Python自然语言处理初学者、NLP工程师及中文文本分析项目开发者&#xff0c;用于快速部署高精度中文分词、词性标注、命名实体识别与依存句法分析能力。压缩包共45个文件&#…

作者头像 李华
网站建设 2026/10/14 14:14:19

ECCV 2020底层视觉论文全景:超分、去噪、去雨雾等方向主线与趋势

1. ECCV 2020底层视觉论文全景&#xff1a;这几条主线值得重点关注图像重建和底层视觉&#xff0c;简单说就是把一张被搞坏的图“救回来”——模糊了想变清晰&#xff0c;下雨了想去掉雨线&#xff0c;雾天看不清路想除雾&#xff0c;噪点多了想降噪&#xff0c;分辨率低了想放…

作者头像 李华
网站建设 2026/10/14 14:13:50

GNN模型部署实战:从单机到线上服务的工程化指南

1. 从单机脚本到线上服务&#xff1a;GNN 部署到底难在哪 很多人做图神经网络&#xff0c;卡在最后一步——模型在 Jupyter Notebook 里跑得挺好&#xff0c;一到要给别人用、要上线、要处理真实流量&#xff0c;就各种问题。我见过太多项目&#xff0c;训练脚本写得漂漂亮亮&a…

作者头像 李华
网站建设 2026/10/14 14:13:40

Linux下用Qt从零实现贪吃蛇:qmake、事件循环与图形界面入门

简介&#xff1a;一份基于Linux与Qt开发的贪吃蛇小游戏完整工程&#xff0c;适合正在学习C/Qt或需要课程设计参考的开发者。项目按功能划分为界面显示、游戏控制、等级管理、背景音乐、英雄榜与帮助等模块&#xff0c;各模块职责清楚&#xff0c;结构清晰&#xff0c;便于阅读和…

作者头像 李华