使用 Apache Pig 处理数据
Hadoop 的普及和其生态系统的不断壮大并不令人感到意外。Hadoop 不断进步的一个特殊领域是 Hadoop 应用程序的编写。虽然编写 Map 和 Reduce 应用程序并不十分复杂,但这些编程确实需要一些软件开发经验。Apache Pig 改变了这种状况,它在 MapReduce 的基础上创建了更简单的过程语言抽象,为 Hadoop 应用程序提供了一种更加接近结构化查询语言 (SQL) 的接口。因此,您不需要编写一个单独的 MapReduce 应用程序,您可以用 Pig Latin 语言写一个脚本,在集群中自动并行处理与分发该脚本。
Pig Latin 示例
让我们从一个简单的 Pig 示例开始介绍,并剖析该示例。Hadoop 的一个有趣的用法是,在大型数据集中搜索满足某个给定搜索条件的记录(在 Linux? 中被称为 grep)。清单 1 显示了在 Pig 中实现该过程的简单性。在所显示的三行代码中,只有一行是真正的搜索。第一行只是将测试数据集(消息日志)读取到代表元组集合的包中。用一个正则表达式来筛选该数据(元组中的惟一条目,表示为 $0 或 field 1),然后查找字符序列 WARN。最后,在主机文件系统中将这个包存储在一个名为 warnings 的新文件中,这个包现在代表来自消息的包含 WARN 的所有元组。
清单 1. 一个简单的 Pig Latin 脚本
messages = LOAD 'messages';
warns = FILTER messages BY $0 MATCHES '.*WARN+.*';
STORE warns INTO 'warnings';
如您所见,这个简单的脚本实现了一个简单的流,但是,如果直接在传统的 MapReduce 模型中实现它,则需要增加大量的代码。这使得学习 Hadoop 并开始使用数据比原始开发容易得多。
现在让我们更深入地探讨 Pig 语言,然后查看该语言的一些功能的其他示例。
--------------------------------------------
回页首
Pig Latin 的基础知识
Pig Latin 是一个相对简单的语言,它可以执行语句。一调语句 就是一个操作,它需要输入一些内容(比如代表一个元组集的包),并发出另一个包作为其输出。一个包 就是一个关系,与表类似,您可以在关系数据库中找到它(其中,元组代表行,并且每个元组都由字段组成)。
用 Pig Latin 编写的脚本往往遵循以下特定格式,从文件系统读取数据,对数据执行一系列操作(以一种或多种方式转换它),然后,将由此产生的关系写回文件系统。您可以在 清单 1 中看到该模式的最简单形式(一个转换)。
Pig 拥有大量的数据类型,不仅支持包、元组和映射等高级概念,还支持简单的数据类型,如 int、long、float、double、chararray 和 bytearray。如果使用简单的类型,您会发现,除了称为 bincond 的条件运算符(其操作类似于 C ternary 运算符)之外,还有其他许多算术运算符(比如 add、subtract、multiply、divide 和 module)。并且,如您所期望的那样,还有一套完整的比较运算符,包括使用正则表达式的丰富匹配模式。
所有 Pig Latin 语句都需要对关系进行操作(并被称为关系运算符)。正如您在 清单 1 中看到的,有一个运算符用于从文件系统加载数据和将数据存储到文件系统中。有一种方式可以通过迭代关系的行来 FILTER 数据。此功能常用于从后续操作不再需要的关系中删除数据。另外,如果您需要对关系的列进行迭代,而不是对行进行迭代,您可以使用 FOREACH 运算符。FOREACH 允许进行嵌套操作,如 FILTER 和 ORDER,以便在迭代过程中转换数据。
ORDER 运算符提供了基于一个或多个字段对关系进行排序的功能。JOIN 运算符基于公共字段执行两个或两个以上的关系的内部或外部联接。SPLIT 运算符提供了根据用户定义的表达式将一个关系拆分成两个或两个以上关系的功能。最后,GROUP 运算符根据某个表达式将数据分组成为一个或多个关系。表 1 提供了 Pig 中的部分关系运算符列表。
表 1. Pig Latin 关系运算符的不完整列表
运算符 描述
FILTER 基于某个条件从关系中选择一组元组。
FOREACH 对某个关系的元组进行迭代,生成一个数据转换。
GROUP 将数据分组为一个或多个关系。
JOIN 联接两个或两个以上的关系(内部或外部联接)。
LOAD 从文件系统加载数据。
ORDER 根据一个或多个字段对关系进行排序。
SPLIT 将一个关系划分为两个或两个以上的关系。
STORE 在文件系统中存储数据。
虽然这不是一个详尽的 Pig Latin 运算符清单,但该表提供了一套在处理大型数据集时非常有用的操作。您可以通过 参考资料 了解完整的 Pig Latin 语言,因为 Pig 有一套不错的在线文档。现在尝试着手编写一些 Pig Latin 脚本,以了解这些运算符的实际工作情况。
--------------------------------------------
回页首
获得 Pig
在有关 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_