在有关 Hadoop 的早期文章中,我采用的方法是将 Hadoop 安装和配置为一个软件包。但 Cloudera 通过用 Linux 将它打包为一个虚拟设备,使得 Hadoop 更易于使用。虽然它是一个较大的下载,但它已预建立并配置了虚拟机 (VM),其中不仅有 Hadoop,还包括了 Apache Hive 和 Pig。因此,利用一个下载和免费提供的 2 型虚拟机管理程序(VirtualBox 或基于内核的虚拟机 [KVM]),您便可以拥有预配置的、已准备就绪的整个 Hadoop 环境。
让 Hadoop 和 Pig 启动并运行
下载完您的特定虚拟机文件之后,需要为您的特定虚拟机管理程序创建一个 VM。在 参考资料 中,您可以找到该操作的分步指南。
Cloudera VM 内存
我发现,仅为虚拟机分配 1GB 的内存时,它无法正常工作。将该内存分配提高至两倍甚至三倍时,它才能够正常运行(也就是说,不会出现 Java? 堆内存的问题)。
一旦创建了自己的 VM,就可以通过 VirtualBox 来启动它,VirtualBox 引导 Linux 内核,并启动所有必要的 Hadoop 守护进程。完成引导后,从创建一个与 Hadoop 和 Pig 通信的终端开始相关操作。
您可以在两种模式中任选一种来使用 Pig。第一种是 Local(本地)模式,它不需要依赖 Hadoop 或 Hadoop 分布式文件系统 (HDFS),在该模式中,所有操作都在本地文件系统上下文中的单一 Java 虚拟机 (JVM) 上执行。另一种模式是 MapReduce 模式,它使用了 Hadoop 文件系统和集群。
Local 模式的 Pig
对于 Local 模式,只需启动 Pig 并用 exectype 选项指定 Local 模式即可。这样做可以将您带入 Grunt 外壳,使您能够以交互方式输入 Pig 语句:
$ pig -x local
...
grunt>
在这里,您能够以交互方式编写 Pig Latin 脚本的代码,并查看每个运算符后面的结果。返回 清单 1,并尝试使用这个脚本(参见 清单 2)。注意,在这种情况下,不需要将数据存储到某个文件中,只需将它转储为一组关系。您可能会在修改后的输出中看到,每个日志行(与 FILTER 定义的搜索条件相匹配)本身就是一个关系(以括号 [()] 为界)。
清单 2. 在 Local 模式中以交互方式使用 Pig
grunt> messages = LOAD '/var/log/messages';
grunt> warns = FILTER messages BY $0 MATCHES '.*WARN+.*';
grunt> DUMP warns
...
(Dec 10 03:56:43 localhost NetworkManager: <WARN> nm_generic_enable_loopback(): error ...
(Dec 10 06:10:18 localhost NetworkManager: <WARN> check_one_route(): (eth0) error ...
grunt>
如果您已经指定 STORE 运算符,那么它会在一个指定名称的目录(而不是一个简单的常规文件)中生成您的数据。
Mapreduce 模式中的 Pig
对于 MapReduce 模式,必须首先确保 Hadoop 正在运行。要做到这一点,最简单的方法是在 Hadoop 文件系统树的根上执行文件列表操作,如 清单 3 所示。
清单 3. 测试 Hadoop 可用性
$ hadoop dfs -ls /
Found 3 items
drwxrwxrwx - hue supergroup
0 2011-12-08 05:20 /tmp
drwxr-xr-x - hue supergroup
0 2011-12-08 05:20 /user
drwxr-xr-x - mapred supergroup
0 2011-12-08 05:20 /var
$
如清单 3 所示,如果 Hadoop 成功运行,此代码的结果会是一个或多个文件组成的??列表。现在,让我们来测试 Pig。从启动 Pig 开始,然后将目录更改为您的 HDFS 根,以确定在 HDFS 中是否可以看到外部所看到的结果(参见 清单 4)。
清单 4. 测试 Pig
$ pig
2011-12-10 06:39:44,276 [main] INFO org.apache.pig.Main - Logging error messages to...
2011-12-10 06:39:44,601 [main] INFO org.apache.pig.... Connecting to hadoop file system at: hdfs://0.0.0.0:8020
2011-12-10 06:39:44,988 [main] INFO org.apache.pig.... connecting to map-reduce job tracker at: 0.0.0.0:8021
grunt> cd hdfs:///
grunt> ls
hdfs://0.0.0.0/tmp
<dir>
hdfs://0.0.0.0/user <dir>
hdfs://0.0.0.0/var
<dir>
grunt>
到目前为止,一切都很好。您可以在 Pig 中看到您的 Hadoop 文件系统,所以,现在请尝试从您的本地主机文件系统将一些数据读取到 HDFS 中。可以通过 Pig 将某个文件从本地复制到 HDFS(参见 清单 5)。
清单 5. 获得一些测试数据
grunt> mkdir test
grunt> cd test
grunt> copyFromLocal /etc/passwd passwd
grunt> ls
hdfs://0.0.0.0/test/passwd<r 1> 1728
接下来,在 Hadoop 文件系统中测试数据现在是安全的,您可以尝试另一个脚本。请注意,您可以在 Pig 内 cat 文件,查看其内容(只是看看它是否存在)。在这个特殊示例中,将确定在 passwd 文件中为用户指定的外壳数量(在 passwd 文件中的最后一列)。
要开始执行该操作,需要从 HDFS 将您的 passwd 文件载入一个 Pig 关系中。在使用 LOAD 运算符之前就要完成该操作,但在这种情况下,您可能希望将密码文件的字段解析为多个独立的字段。在本例中,我们指定了 PigStorage 函数,您可以使用它来显示文件的分隔符(本例中,是冒号 [:] 字符)。您也可以用 AS 关键字指定独立字段(或架构),包括它们的独立类型(参见 清单 6)。
清单 6. 将文件读入一个关系中
grunt> passwd = LOAD '/etc/passwd' USING PigStorage(':') AS (user:chararray, passwd:chararray, uid:int, gid:int, userinfo:chararray, home:chararray, shell:chararray);
grunt> DUMP passwd;
(root,x,0,0,root,/root,/bin/bash)
(bin,x,1,1,bin,/bin,/sbin/nologin)
...
(cloudera,x,500,500,,/home/cloudera,/bin/bash)
grunt>
接下来,使用 GROUP 运算符根据元组的外壳将元组分组到该关系中(参见 清单 7)。再次转储此关系,这样做只是为了说明 GROUP 运算符的结果。注意,在这里,您需要根据元组正使用的特定外壳(在开始时指定的外壳)对元组进行分组(作为一个内部包)。
清单 7. 将元组分组为其外壳的一个函数
grunt> grp_shell = GROUP passwd BY shell;
grunt> DUMP grp_shell;
(/bin/bash,{(cloudera,x,500,500,,/home/cloudera,/bin/bash),(root,x,0,0,...), ...})
(/bin/sync,{(sync,x,5,0,sync,/sbin,/bin/sync)})
(/sbin/shutdown,{(shutdown,x,6,0,shutdown,/sbin,/sbin/shutdown)})
grunt>
但是,您想要的是在 passwd 文件中指定的独特外壳的计数。所以,需要使用 FOREACH 运算符来遍历分组中的每个元组,COUNT 出现的数量(参见 清单 8)。
清单 8. 利用每个外壳的计数对结果进行分组
grunt> counts = FOREACH grp_shell GENERATE group, COUNT(passwd);
grunt> DUMP counts;
...
(/bin/bash,5)
(/bin/sync,1)
(/bin/false,1)
(/bin/halt,1)
(/bin/nologin,27)
(/bin/shutdown,1)
grunt>
备注:如果要将该代码作为一个脚本来执行,只需将脚本输入到某个文件中,然后使用 pig myscript.pig 来执行它。