测试 Hadoop
既然已经安装了 Hadoop 并测试了文件系统的基本接口,现在就该在真实的应用程序中测试 Hadoop 了。在这个示例中,我们使用 MapReduce 处理一个小数据集。map(映射) 和 reduce(缩减) 源自函数式编程中的函数名,但是这个应用程序的核心功能是数据缩减。映射 是指把大量输入处理成更小的子问题集(然后把这些子问题分发给并行的工作系统)。缩减 是指把子问题的答案组合成单一输出集。注意,这里没有定义处理 的含义,因为框架允许您自己定义什么是处理。典型的 MapReduce 示例是计算单词在文档集中出现的频率。
根据前面的讨论,我们需要一个输入集并产生一个输出集。第一步是在文件系统中创建一个 input 子目录,工作将放在这个目录中。使用以下命令:
接下来,在 input 目录中放一些工作。在这里,使用 put 命令把文件从本地文件系统转移到 HDFS 中(见清单 4)。注意,下面的命令格式把源文件转移到 HDFS 子目录 (input) 中。完成之后,在 HDFS 中就有两个文本文件等待处理。
清单 4. 把文件转移到 HDFS 中
# hadoop-0.20 fs -put /usr/src/linux-source-2.6.27/Doc*/rt-mutex-design.txt input
#
接下来,使用 ls 命令检查文件是否存在(见清单 5)。
清单 5. 检查 HDFS 中的文件
Found 2 items
-rw-r--r-- 1 root supergroup 78031 2010-04-29 17:35 /user/root/input/memory-barriers.txt
-rw-r--r-- 1 root supergroup 33567 2010-04-29 17:36 /user/root/input/rt-mutex-design.txt
#
确认工作已经放在 HDFS 中之后,就可以执行 MapReduce 函数了。这个函数只需要一个命令,但是需要很长的请求,见清单 6。这个命令请求执行一个 JAR。它实际上实现许多功能,但是这个示例只使用 wordcount。jobtracker 守护进程请求 datanode 执行 MapReduce 作业,这会产生相当多的输出(这里的输出比较少是因为只处理两个文件)。它显示 map 和 reduce 函数的进度,然后提供与文件系统的 I/O 和记录处理相关的统计数据。
清单 6. 执行计算单词频率的 MapReduce 作业
wordcount input output
10/04/29 17:36:49 INFO input.FileInputFormat: Total input paths to process : 2
10/04/29 17:36:49 INFO mapred.JobClient: Running job: job_201004291628_0009
10/04/29 17:36:50 INFO mapred.JobClient: map 0% reduce 0%
10/04/29 17:37:00 INFO mapred.JobClient: map 100% reduce 0%
10/04/29 17:37:06 INFO mapred.JobClient: map 100% reduce 100%
10/04/29 17:37:08 INFO mapred.JobClient: Job complete: job_201004291628_0009
10/04/29 17:37:08 INFO mapred.JobClient: Counters: 17
10/04/29 17:37:08 INFO mapred.JobClient: Job Counters
10/04/29 17:37:08 INFO mapred.JobClient: Launched reduce tasks=1
10/04/29 17:37:08 INFO mapred.JobClient: Launched map tasks=2
10/04/29 17:37:08 INFO mapred.JobClient: Data-local map tasks=2
10/04/29 17:37:08 INFO mapred.JobClient: FileSystemCounters
10/04/29 17:37:08 INFO mapred.JobClient: FILE_BYTES_READ=47556
10/04/29 17:37:08 INFO mapred.JobClient: HDFS_BYTES_READ=111598
10/04/29 17:37:08 INFO mapred.JobClient: FILE_BYTES_WRITTEN=95182
10/04/29 17:37:08 INFO mapred.JobClient: HDFS_BYTES_WRITTEN=30949
10/04/29 17:37:08 INFO mapred.JobClient: Map-Reduce Framework
10/04/29 17:37:08 INFO mapred.JobClient: Reduce input groups=2974
10/04/29 17:37:08 INFO mapred.JobClient: Combine output records=3381
10/04/29 17:37:08 INFO mapred.JobClient: Map input records=2937
10/04/29 17:37:08 INFO mapred.JobClient: Reduce shuffle bytes=47562
10/04/29 17:37:08 INFO mapred.JobClient: Reduce output records=2974
10/04/29 17:37:08 INFO mapred.JobClient: Spilled Records=6762
10/04/29 17:37:08 INFO mapred.JobClient: Map output bytes=168718
10/04/29 17:37:08 INFO mapred.JobClient: Combine input records=17457
10/04/29 17:37:08 INFO mapred.JobClient: Map output records=17457
10/04/29 17:37:08 INFO mapred.JobClient: Reduce input records=3381
处理结束之后,检查结果。这个作业的作用是计算单词在输入文件中出现的次数。输出是一个包含元组的文件,元组表示单词和它在输入中出现的次数。找到输出文件之后,可以通过 hadoop-0.20 实用程序使用 cat 命令查看数据(见清单 7)。
清单 7. 检查 MapReduce wordcount 操作的输出
Found 2 items
drwxr-xr-x - root supergroup 0 2010-04-29 17:36 /user/root/output/_logs
-rw-r--r-- 1 root supergroup 30949 2010-04-29 17:37 /user/root/output/part-r-00000
#
# hadoop-0.20 fs -cat output/part-r-00000 | head -13
!= 1
"Atomic 2
"Cache 2
"Control 1
"Examples 1
"Has 7
"Inter-CPU 1
"LOAD 1
"LOCK" 1
"Locking 1
"Locks 1
"MMIO 1
"Pending 5
#
还可以使用 hadoop-0.20 实用程序从 HDFS 中提取文件(见清单 8)。只需使用 get 实用程序(它与前面在 HDFS 中写文件所用的 put 相似)。对于 get 操作,指定 HDFS 中要提取的文件(来自 output 子目录)和在本地文件系统中要写的文件 (output.txt)。
清单 8. 从 HDFS 提取输出
# cat output.txt | head -5
!= 1
"Atomic 2
"Cache 2
"Control 1
"Examples 1
#
我们再来看一个示例,它使用相同的 JAR,但是目的不同(在这里要试验并行的 grep)。对于这个测试,仍然使用现有的输入文件,但是要删除 output 子目录以便在测试时重新创建它:
Deleted hdfs://localhost/user/root/output
接下来,请求用于执行 grep 的 MapReduce 作业。在这种情况下,并行执行 grep(映射),然后组合 grep 的结果(缩减)。清单 9 给出这个使用模型的输出(为了简短,这里删除了一些输出)。注意,这里的命令请求是一个 grep,它从 input 子目录获取输入,把结果放在 output 子目录中。最后一个参数是要搜索的字符串(在这里是 'kernel')。
清单 9. 执行单词搜索计数的 MapReduce 作业 (grep)
grep input output 'kernel'
10/04/30 09:22:29 INFO mapred.FileInputFormat: Total input paths to process : 2
10/04/30 09:22:30 INFO mapred.JobClient: Running job: job_201004291628_0010
10/04/30 09:22:31 INFO mapred.JobClient: map 0% reduce 0%
10/04/30 09:22:42 INFO mapred.JobClient: map 66% reduce 0%
10/04/30 09:22:45 INFO mapred.JobClient: map 100% reduce 0%
10/04/30 09:22:54 INFO mapred.JobClient: map 100% reduce 100%
10/04/30 09:22:56 INFO mapred.JobClient: Job complete: job_201004291628_0010
10/04/30 09:22:56 INFO mapred.JobClient: Counters: 18
10/04/30 09:22:56 INFO mapred.JobClient: Job Counters
10/04/30 09:22:56 INFO mapred.JobClient: Launched reduce tasks=1
10/04/30 09:22:56 INFO mapred.JobClient: Launched map tasks=3
10/04/30 09:22:56 INFO mapred.JobClient: Data-local map tasks=3
10/04/30 09:22:56 INFO mapred.JobClient: FileSystemCounters
10/04/30 09:22:56 INFO mapred.JobClient: FILE_BYTES_READ=57
10/04/30 09:22:56 INFO mapred.JobClient: HDFS_BYTES_READ=113144
10/04/30 09:22:56 INFO mapred.JobClient: FILE_BYTES_WRITTEN=222
10/04/30 09:22:56 INFO mapred.JobClient: HDFS_BYTES_WRITTEN=109
...
10/04/30 09:23:14 INFO mapred.JobClient: Map output bytes=15
10/04/30 09:23:14 INFO mapred.JobClient: Map input bytes=23
10/04/30 09:23:14 INFO mapred.JobClient: Combine input records=0
10/04/30 09:23:14 INFO mapred.JobClient: Map output records=1
10/04/30 09:23:14 INFO mapred.JobClient: Reduce input records=1
#
作业完成之后,检查 output 目录,找到结果文件,然后通过执行文件系统 cat 操作查看其内容(见清单 10)。
清单 10. 检查 MapReduce 作业的输出
Found 2 items
drwxr-xr-x - root supergroup 0 2010-04-30 09:22 /user/root/output/_logs
-rw-r--r-- 1 root supergroup 10 2010-04-30 09:23 /user/root/output/part-00000
# hadoop-0.20 fs -cat output/part-00000
17 kernel
#