R-和-Hadoop-大数据分析-全-
R 和 Hadoop 大数据分析(全)
原文:
annas-archive.org/md5/b7f3a14803c1b4d929732471e0b28932译者:飞龙
前言
企业每天获取的数据量呈指数增长。现在可以将这些海量信息存储在像 Hadoop 这样的低成本平台上。
这些组织目前面临的难题是如何处理这些数据,以及如何从中提取关键见解。因此,R 就成为了关键工具。R 是一个非常强大的工具,它使得在数据上运行高级统计模型变得轻而易举,将得到的模型转换为多彩的图表和可视化,并且执行更多与数据科学相关的功能。
然而,R 的一个主要缺点是它的可扩展性较差。核心的 R 引擎只能处理有限数量的数据。由于 Hadoop 在大数据处理方面非常流行,将 R 与 Hadoop 结合以实现可扩展性成为下一步的合理选择。
本书专门讲解 R 和 Hadoop 以及如何利用 Hadoop 平台使 R 的数据分析操作具备可扩展性。
本书将面向广泛的受众,包括数据科学家、统计学家、数据架构师和工程师,帮助他们使用 R 和 Hadoop 处理和分析大量信息。
使用 R 与 Hadoop 结合,将提供一个弹性的 数据分析平台,能够根据待分析数据集的大小进行扩展。经验丰富的程序员可以在 R 中编写 Map/Reduce 模块,并通过 Hadoop 的并行处理 Map/Reduce 机制运行这些模块,从而识别数据集中的模式。
介绍 R
R 是一个开源软件包,用于对数据进行统计分析。R 是一种编程语言,数据科学家、统计学家和其他需要进行数据统计分析并通过回归、聚类、分类、文本分析等机制从数据中提取关键信息的人群都会使用。R 在 GNU(通用公共许可证)下注册。它由新西兰奥克兰大学的 Ross Ihaka 和 Robert Gentleman 开发,目前由 R 开发核心团队管理。它可以被视为 S 语言的另一种实现,S 是由 Johan Chambers 在贝尔实验室开发的。尽管存在一些重要的差异,但用 S 编写的大多数代码可以通过 R 解释器引擎无缝运行。
R 提供了多种统计、机器学习(线性与非线性建模、经典统计检验、时间序列分析、分类、聚类)和图形技术,并且具有高度的扩展性。R 拥有多种内建及扩展功能,适用于统计、机器学习和可视化任务,包括:
-
数据提取
-
数据清洗
-
数据加载
-
数据转换
-
统计分析
-
预测建模
-
数据可视化
这是目前市场上最流行的开源统计分析包之一。它跨平台,拥有非常广泛的社区支持,以及一个庞大且不断壮大的用户社区,每天都在新增包。随着包列表的增长,R 现在可以连接到其他数据存储,如 MySQL、SQLite、MongoDB 和 Hadoop 进行数据存储活动。
了解 R 的特性
让我们来看一下 R 的不同有用功能:
-
有效的编程语言
-
关系型数据库支持
-
数据分析
-
数据可视化
-
通过丰富的 R 包库进行扩展
研究 R 语言的流行度
KD 提供的图表显示,R 是进行数据分析和挖掘的最流行语言:

以下图表提供了从 2005 年到 2013 年,R 用户发布的 R 包的总数。这就是我们探索 R 用户的方式。2012 年的增长呈指数级,2013 年似乎也有望超过这一增长。
R 允许通过各种统计和机器学习操作执行数据分析,具体如下:
-
回归
-
分类
-
聚类
-
推荐
-
文本挖掘

介绍大数据
大数据需要处理大量且复杂的数据集,这些数据集可以是结构化的、半结构化的或非结构化的,并且通常无法完全加载到内存中进行处理。它们必须就地处理,这意味着计算必须在数据所在的地方进行。当我们与开发人员交谈时,这些实际构建大数据系统和应用程序的人,我们对他们所说的 3V 有了更清晰的了解。他们通常会提到大数据的 3V 模型,即速度(velocity)、体量(volume)和多样性(variety)。
速度指的是应用分析所需的低延迟、实时速度。一个典型的例子是对来自社交网络网站或多个不同数据源的连续数据流进行分析。
体量指的是数据集的大小。根据生成或接收数据的应用程序类型,数据大小可能为 KB、MB、GB、TB 或 PB。
多样性指的是数据可能存在的各种类型,例如文本、音频、视频和图片。
大数据通常包括具有不同大小的数据集。这些系统在规定的时间内处理如此大量数据几乎是不可能的。大数据的体量是一个不断变化的目标,截至 2012 年,单一数据集的大小范围从几十个 TB 到多个 PB 不等。面对这一看似不可逾越的挑战,完全新的平台被称为大数据平台。

获取关于持有大数据的著名组织的信息
一些持有大数据的著名组织如下:
-
Facebook:它拥有 40 PB 的数据,每天捕获 100 TB 的数据
-
Yahoo!:它拥有 60 PB 的数据
-
Twitter:它每天捕获 8 TB 数据
-
eBay:它有 40 PB 的数据,每天捕获 50 TB 数据
被视为大数据的数据量因公司而异。虽然一个公司的大数据对于另一个公司来说可能是小数据,但有些共同点:无法完全装入内存或磁盘,数据流入迅速,需要处理,并且可以从分布式软件栈中受益。对于一些公司来说,10 TB 的数据会被视为大数据,而对其他公司来说,1 PB 的数据才是大数据。所以,只有你能确定数据是否真的是大数据。可以说,它通常会从低 TB 范围开始。
另一个值得问的问题是,既然你没有捕捉和保留足够的数据,你认为自己现在没有大数据问题吗?在某些情况下,企业会字面上丢弃数据,因为没有经济高效的方式来存储和处理它。通过像 Hadoop 这样的平台,可以开始捕获和存储所有这些数据。
介绍 Hadoop
Apache Hadoop 是一个开源的 Java 框架,用于在大规模的商品硬件集群上处理和查询大量数据。Hadoop 是一个顶级的 Apache 项目,由 Yahoo!和 Doug Cutting 发起并领导。它依赖来自世界各地的活跃社区贡献者的支持,才能取得成功。
在 Yahoo!的大力技术投资下,Apache Hadoop 已经成为企业级云计算技术。它正逐渐成为大数据处理的行业事实框架。
Hadoop 改变了大规模计算的经济学和动态。其影响可以归结为四个显著特点。Hadoop 实现了可扩展、具有成本效益、灵活且容错的解决方案。
探索 Hadoop 功能
Apache Hadoop 具有两个主要特点:
-
HDFS(Hadoop 分布式文件系统)
-
MapReduce
学习 Hadoop 组件
Hadoop 包括一个生态系统,其中包含在核心 HDFS 和 MapReduce 层之上构建的其他产品,用于支持平台上的各种操作。以下是一些流行的 Hadoop 组件:
-
Mahout:这是一个广泛的机器学习算法库。
-
Pig:Pig 是一种高级语言(如 PERL),用于分析大数据集,具有自己的语言语法来表达数据分析程序,并配备了评估这些程序的基础设施。
-
Hive:Hive 是一个为 Hadoop 设计的数据仓库系统,它简化了数据汇总、临时查询和对存储在 HDFS 中的大数据集的分析。它有自己的类似 SQL 的查询语言,称为 Hive 查询语言(HQL),用于向 Hadoop 发出查询命令。
-
HBase:HBase(Hadoop 数据库)是一个分布式、面向列的数据库。HBase 使用 HDFS 作为底层存储。它支持使用 MapReduce 进行批处理计算和原子查询(随机读取)。
-
Sqoop:Apache Sqoop 是一个工具,旨在高效地在 Hadoop 与结构化关系型数据库之间传输大规模数据。Sqoop是(SQ)L 到 Had(oop)的缩写。
-
ZooKeeper:ZooKeeper 是一个集中式服务,用于维护配置信息、命名、提供分布式同步和组服务,这些对于各种分布式系统非常有用。
-
Ambari:一个基于 Web 的工具,用于配置、管理和监控 Apache Hadoop 集群,支持 Hadoop HDFS、Hadoop MapReduce、Hive、HCatalog、HBase、ZooKeeper、Oozie、Pig 和 Sqoop。
理解为何要将 R 与 Hadoop 结合使用
我还想说,有时数据存储在 HDFS 中(以各种格式)。由于许多数据分析师在 R 中非常高效,因此使用 R 处理通过 Hadoop 相关工具存储的数据是非常自然的。
如前所述,R 的优势在于其能够通过丰富的包库进行数据分析,但在处理非常大的数据集时则显得力不从心。而 Hadoop 的优势则在于能够存储和处理 TB 甚至 PB 范围内的海量数据。如此庞大的数据集无法完全放入内存,因为每台机器的 RAM 无法容纳如此大的数据集。解决方法是对有限的数据块进行分析,也称为采样,或者将 R 的分析能力与 Hadoop 的存储和处理能力结合,最终得到理想的解决方案。这样的解决方案还可以通过云平台(如 Amazon EMR)实现。
本书内容介绍
第一章,准备使用 R 与 Hadoop,介绍了 R 与 Hadoop 的基本信息以及安装过程。
第二章,编写 Hadoop MapReduce 程序,涵盖了 Hadoop MapReduce 的基础知识以及使用 Hadoop 执行 MapReduce 的方法。
第三章,R 与 Hadoop 的集成,展示了通过各种数据处理过程部署和运行 RHadoop 和 RHIPE 的示例 MapReduce 程序。
第四章,使用 Hadoop Streaming 与 R,展示了如何在 R 中使用 Hadoop Streaming。
第五章,使用 R 与 Hadoop 学习数据分析,通过展示实际的数据分析问题来介绍数据分析项目的生命周期。
第六章,通过机器学习理解大数据分析,介绍了如何使用机器学习技术通过 RHadoop 进行大数据分析。
第七章,从各种数据库导入和导出数据,介绍了如何与流行的关系数据库接口,以便使用 R 进行数据的导入和导出操作。
附录,参考文献,描述了所有章节内容相关的额外资源链接。
本书所需内容
由于我们将使用 R 和 Hadoop 进行大数据分析,您应具备基本的 R 和 Hadoop 知识,并了解如何进行实际操作。此外,您需要安装并配置好 R 和 Hadoop。如果您已经拥有较大规模的数据和可以通过数据驱动技术(如 R 和 Hadoop 函数)解决的问题,那将是非常有帮助的。
本书的目标读者
本书非常适合那些希望利用 Hadoop 进行大数据分析的 R 开发者。他们希望掌握 R 与 Hadoop 的所有集成技巧,学习如何编写 Hadoop MapReduce,以及如何在 R 中开发和运行 Hadoop MapReduce 的教程。本书也适用于那些了解 Hadoop 并希望利用 R 包在大数据上构建智能应用程序的人。如果读者有基本的 R 知识将更有帮助。
约定
本书中有多种文本样式,用来区分不同类型的信息。以下是这些样式的一些示例及其含义的解释。
文本中的代码词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟网址、用户输入和 Twitter 用户名等会以如下形式显示:"准备Map()输入。"
代码块的格式如下:
<property>
<name>mapred.job.tracker</name>
<value>localhost:54311</value>
<description>The host and port that the MapReduce job tracker runs
at. If "local", then jobs are run in-process as a single map
and reduce task.
</description>
</property>
任何命令行输入或输出均按如下格式书写:
// Setting the environment variables for running Java and Hadoop commands
export HADOOP_HOME=/usr/local/hadoop
export JAVA_HOME=/usr/lib/jvm/java-6-sun
新术语和重要词汇以粗体显示。您在屏幕上看到的单词,例如菜单或对话框中的单词,会以这种形式出现在文本中:"打开密码选项卡。"
注意
警告或重要注意事项会以框体的形式显示。
提示
提示和技巧会像这样展示。
读者反馈
我们始终欢迎读者的反馈。让我们知道您对这本书的看法——您喜欢的内容或者可能不喜欢的地方。读者的反馈对我们非常重要,它能帮助我们开发出您能从中获得最大价值的书籍。
若要向我们发送一般性反馈,请通过电子邮件 <feedback@packtpub.com> 与我们联系,并在邮件主题中提到书名。
如果您擅长某个主题,并且有兴趣编写或贡献一本书,请参阅我们在www.packtpub.com/authors上的作者指南。
客户支持
现在,您已经成为一本 Packt 书籍的骄傲拥有者,我们提供了多种帮助您最大化购买价值的资源。
下载示例代码
您可以从您的帐户下载所有 Packt 书籍的示例代码文件,网址为www.packtpub.com。如果您在其他地方购买了本书,可以访问www.packtpub.com/support,注册后我们将直接通过电子邮件发送文件给您。
勘误
虽然我们已尽一切努力确保内容的准确性,但错误确实会发生。如果您在我们的书籍中发现错误——可能是文本或代码中的错误——我们将不胜感激地请您向我们报告。通过这样做,您可以帮助其他读者避免沮丧,并帮助我们改进本书的后续版本。如果您发现任何勘误,请访问www.packtpub.com/submit-errata,选择您的书籍,点击勘误提交表格链接,并输入您的勘误细节。一旦确认您的勘误,您的提交将被接受,并将勘误上传到我们的网站上,或添加到任何现有勘误列表中,添加到该书籍的勘误部分。可以通过访问www.packtpub.com/support来查看任何现有的勘误。
海盗行为
互联网上侵犯版权材料的盗版问题是所有媒体都在不断面对的问题。在 Packt,我们非常重视我们版权和许可的保护。如果您在任何形式的互联网上发现我们作品的非法副本,请立即向我们提供位置地址或网站名称,以便我们采取措施。
请通过<copyright@packtpub.com>联系我们,并附上涉嫌侵权材料的链接。
我们感谢您帮助我们保护作者和为您提供有价值的内容的能力。
问题
如果您在阅读本书的过程中遇到任何问题,可以通过<questions@packtpub.com>与我们联系,我们将尽力解决。
第一章:开始使用 R 和 Hadoop
第一章已经包含了 R 和 Hadoop 基础的多个主题,如下所示:
-
R 安装、功能和数据建模
-
Hadoop 安装、功能和组件
在前言中,我们向你介绍了 R 和 Hadoop。本章将重点帮助你开始使用这两项技术。到目前为止,R 主要用于统计分析,但由于功能和包的不断增加,它在多个领域变得流行,例如机器学习、可视化和数据操作。R 不会将所有数据(大数据)加载到机器内存中,因此,可以选择 Hadoop 来加载数据作为大数据。并非所有算法都能在 Hadoop 上运行,而且这些算法通常不是 R 算法。尽管如此,使用 R 进行分析时,仍然存在与大数据相关的若干问题。为了分析数据集,R 会将其加载到内存中,而如果数据集很大,通常会因“无法分配大小为 x 的向量”等异常而失败。因此,为了处理大数据集,结合 R 与 Hadoop 集群的计算能力,可以大大增强 R 的处理能力。Hadoop 是一个非常流行的框架,提供了并行处理能力。因此,我们可以在 Hadoop 集群上使用 R 算法或分析处理来完成工作。

如果我们考虑将 R 和 Hadoop 结合使用,R 将负责数据分析操作,包括数据加载、探索、分析和可视化等初步功能,而 Hadoop 将负责并行数据存储及处理分布式数据的计算能力。
在可负担得起的大数据技术出现之前,分析通常是在单台计算机上的有限数据集上运行的。当应用到大数据集时,高级机器学习算法非常有效,而这仅能在数据可以通过分布式数据存储系统进行存储和处理的大型集群中实现。在接下来的章节中,我们将介绍如何在不同操作系统上安装 R 和 Hadoop,以及将 R 和 Hadoop 链接的可能方式。
安装 R
你可以访问 R 官方网站下载合适的版本。
这里提供了三种不同操作系统的步骤。我们已考虑了 Windows、Linux 和 Mac OS 来安装 R。下载最新版本的 R,因为它将包含所有最新的修补程序和解决过去 bug 的版本。
对于 Windows,按照以下步骤进行操作:
-
点击 CRAN 部分,选择 CRAN 镜像,然后选择你的 Windows 操作系统(坚持使用 Linux;Hadoop 几乎总是在 Linux 环境中使用)。
-
从镜像站点下载最新的 R 版本。
-
执行下载的
.exe文件以安装 R。
对于 Linux-Ubuntu,按照以下步骤进行操作:
-
点击CRAN部分,选择CRAN 镜像,然后选择你的操作系统。
-
在
/etc/apt/sources.list文件中添加 CRAN<mirror>条目。 -
使用
sudo apt-get update命令从仓库下载并更新包列表。 -
使用
sudo apt-get install r-base命令安装 R 系统。
对于 Linux-RHEL/CentOS,请按照以下步骤操作:
-
点击CRAN,选择CRAN 镜像,然后选择 Red Hat 操作系统。
-
下载
R-*core-*.rpm文件。 -
使用
rpm -ivh R-*core-*.rpm命令安装.rpm包。 -
使用
sudo yum install R命令安装 R 系统。
对于 Mac,请按照以下步骤操作:
-
点击CRAN,选择CRAN 镜像,然后选择你的操作系统。
-
下载以下文件:
pkg、gfortran-*.dmg和tcltk-*.dmg。 -
安装
R-*.pkg文件。 -
然后,安装
gfortran-*.dmg和tcltk-*.dmg文件。
在安装基础 R 包后,建议安装 RStudio,这是一个功能强大且直观的集成开发环境(IDE)用于 R 语言。
提示
我们可以使用 Revolution Analytics 提供的 R 发行版作为现代数据分析工具,进行统计计算和预测分析,该工具提供免费版和付费版。还支持 Hadoop 集成,可进行大数据分析。
安装 RStudio
要安装 RStudio,请执行以下步骤:
-
下载适用于你的操作系统的最新版本 RStudio。
-
执行安装程序文件并安装 RStudio。
RStudio 组织和用户社区已经开发了许多用于图形和可视化的 R 包,如 ggplot2、plyr、Shiny、Rpubs 和 devtools。
理解 R 语言的特性
目前有超过 3,000 个 R 包,并且这个数量每天都在增长。试图在任何一本书中解释所有这些包将超出其范围。本书只关注 R 的关键特性以及最常用和最受欢迎的包。
使用 R 包
R 包是 R 功能的自包含单元,可以作为函数调用。一个很好的类比是 Java 中的 .jar 文件。R 包库庞大,涵盖了各种操作,从统计运算、机器学习到丰富的图形可视化和绘图。每个包将包含一个或多个 R 函数。R 包是一个可重用的实体,可以被他人共享和使用。R 用户可以安装包含所需功能的包并开始调用包中的函数。一个全面的包列表可以在 cran.r-project.org/ 中找到,称为综合 R 档案网络(CRAN)。
执行数据操作
R 可以进行广泛的操作。统计操作,如均值、最小值、最大值、概率、分布和回归。机器学习操作,如线性回归、逻辑回归、分类和聚类。通用数据处理操作如下:
-
数据清理:此选项用于清理大量数据集。
-
数据探索:此选项用于探索数据集的所有可能值。
-
数据分析:此选项用于对数据进行描述性和预测性分析数据可视化,即分析输出编程的可视化。
为了构建一个有效的分析应用程序,有时我们需要使用在线 应用程序编程接口(API)来挖掘数据,通过便捷的服务进行分析,并通过第三方服务进行可视化。此外,要自动化数据分析过程,编程将是最有用的功能。
R 拥有自己的编程语言来处理数据。此外,可用的包可以帮助将 R 与其他编程功能集成。R 支持面向对象编程概念。它还能够与其他编程语言(如 Java、PHP、C 和 C++)进行集成。有多个包作为中间层编程功能,帮助进行数据分析,这些包类似于 sqldf、httr、RMongo、RgoogleMaps、RGoogleAnalytics 和 google-prediction-api-r-client。
增强社区支持
随着 R 用户数量的增加,相关的 R 小组也在不断增多。因此,R 学习者或开发者可以轻松地与其他人连接,并借助多个 R 小组或社区解决他们的疑惑。
以下是一些可以找到有用的流行资源:
-
R 邮件列表:这是 R 项目所有者创建的官方 R 小组。
-
R 博客:R 拥有无数的博客作者,他们在多个 R 应用领域进行写作。最受欢迎的博客网站之一是
www.r-bloggers.com/,所有的博客作者都会在该网站贡献自己的博客。 -
Stack Overflow:这是一个很棒的技术知识分享平台,程序员可以在这里发布技术问题,热心的程序员会提供解决方案。欲了解更多信息,请访问
stats.stackexchange.com/。 -
小组:在 LinkedIn 和 Meetup 上还存在许多其他小组,全球的专业人士会聚集在一起讨论他们的问题和创新想法。
-
书籍:关于 R 的书籍也有很多。其中一些受欢迎的书籍包括 《R 实战》,作者 Rob Kabacoff,Manning 出版社;《R 速查手册》,作者 Joseph Adler,O'Reilly Media;《R 与数据挖掘》,作者 Yanchang Zhao,Academic Press;以及 《R 图形 cookbook》,作者 Hrishi Mittal,Packt Publishing。
在 R 中进行数据建模
数据建模是一种机器学习技术,用于从历史数据集中识别隐藏的模式,这些模式将有助于在相同数据上进行未来值预测。这些技术高度关注过去用户的行为并学习他们的偏好。许多流行的组织已经采纳了这些数据建模技术,以根据客户的过去交易来了解他们的行为。这些技术将分析数据并预测客户在寻找什么。Amazon、Google、Facebook、eBay、LinkedIn、Twitter 等众多组织正在使用数据挖掘来改变定义应用程序。
最常见的数据挖掘技术如下:
-
回归:在统计学中,回归是一种经典技术,用于通过拟合变量值的状态线来识别两个或多个变量之间的标量关系。这种关系将帮助预测未来事件中变量的值。例如,任何变量 y 可以被建模为另一个变量 x 的线性函数,公式为y = mx+c。其中,x 是预测变量,y 是响应变量,m 是直线的斜率,c 是截距。产品或服务的销售预测以及股票价格预测可以通过这种回归方法实现。R 通过
lm方法提供了这一回归功能,默认情况下,该方法已存在于 R 中。 -
分类:这是一种机器学习技术,用于标记提供的训练示例集的观察结果。通过这种方法,我们可以将观察结果分类为一个或多个标签。销售可能性、在线欺诈检测和癌症分类(医学科学)是分类问题的常见应用。Google Mail 使用此技术将电子邮件分类为垃圾邮件或非垃圾邮件。在 R 中,
glm、glmnet、ksvm、svm和randomForest方法可以用于分类功能。 -
聚类:这种技术的核心是将相似的项目从给定的集合中组织成组。用户细分和图像压缩是聚类技术的最常见应用。市场细分、社交网络分析、计算机集群组织以及天文数据分析都是聚类的应用。Google 新闻利用这些技术将相似的新闻项分组到同一类别中。在 R 中,可以通过
knn、kmeans、dist、pvclust和Mclust方法实现聚类。 -
推荐:推荐算法用于推荐系统,而这些系统是当今最容易识别的机器学习技术。Web 内容推荐可能包括类似的网站、博客、视频或相关内容。此外,在线物品的推荐对于交叉销售和追加销售也非常有帮助。我们都见过在线购物门户,尝试根据用户的过去行为推荐书籍、手机或任何可以在网上销售的商品。Amazon 是一个知名的电子商务门户,通过推荐系统生成了 29% 的销售额。推荐系统可以通过
Recommender()和 R 中的recommenderlab包来实现。
安装 Hadoop
现在,我们假设你已经了解了 R,它是什么,如何安装,主要特点是什么,以及为什么你可能想要使用它。接下来,我们需要了解 R 的局限性(这也是介绍 Hadoop 的一个更好的方式)。在处理数据之前,R 需要将数据加载到 随机存取存储器 (RAM) 中。因此,数据需要小于可用的机器内存。对于大于机器内存的数据,我们将其视为大数据(仅在我们的情况下,因为大数据有很多其他定义)。
为了避免大数据问题,我们需要扩展硬件配置;然而,这只是一个临时解决方案。要解决这个问题,我们需要一个能够存储数据并在大型计算机集群上执行并行计算的 Hadoop 集群。Hadoop 是最流行的解决方案。Hadoop 是一个开源的 Java 框架,是由 Apache 软件基金会处理的顶级项目。Hadoop 的灵感来自 Google 文件系统和 MapReduce,主要设计用于通过分布式处理操作大数据。
Hadoop 主要支持 Linux 操作系统。在 Windows 上运行 Hadoop,我们需要使用 VMware 在 Windows 操作系统中托管 Ubuntu。有许多使用和安装 Hadoop 的方法,但在这里我们将考虑最适合 R 的方式。在结合 R 和 Hadoop 之前,我们先来了解一下 Hadoop 是什么。
提示
机器学习包含所有数据建模技术,可以通过这个网页链接 en.wikipedia.org/wiki/Machine_learning 进行探索。
由 Michael Noll 撰写的 Hadoop 安装结构博客可以在 www.michael-noll.com/tutorials/running-hadoop-on-ubuntu-linux-single-node-cluster/ 上找到。
理解不同的 Hadoop 模式
Hadoop 有三种不同的模式:
-
独立模式:在此模式下,您无需启动任何 Hadoop 守护进程。只需调用
~/Hadoop-directory/bin/hadoop,它将作为单一 Java 进程执行 Hadoop 操作。此模式推荐用于测试。它是默认模式,您无需配置任何其他内容。所有守护进程,如 NameNode、DataNode、JobTracker 和 TaskTracker 都在一个 Java 进程中运行。 -
伪模式:在此模式下,您为所有节点配置 Hadoop。为每个 Hadoop 组件或守护进程(如单主机上的迷你集群)启动单独的 Java 虚拟机(JVM)。
-
完全分布式模式:在此模式下,Hadoop 会分布到多台机器上。为 Hadoop 组件配置专用主机。因此,每个守护进程都有独立的 JVM 进程。
理解 Hadoop 安装步骤
Hadoop 可以通过多种方式安装;我们将考虑与 R 集成更好的方式。我们将选择 Ubuntu 操作系统,因为它易于安装和访问。
-
在 Linux 上安装 Hadoop,Ubuntu 版本(单节点和多节点集群)。
-
在 Ubuntu 上安装 Cloudera Hadoop。
在 Linux 上安装 Hadoop,Ubuntu 版本(单节点集群)
要在 Ubuntu 操作系统上以伪模式安装 Hadoop,我们需要满足以下先决条件:
-
Sun Java 6
-
专用 Hadoop 系统用户
-
配置 SSH
-
禁用 IPv6
提示
提供的 Hadoop 安装将支持 Hadoop MRv1。
按照以下步骤安装 Hadoop:
-
从 Apache 软件基金会下载最新的 Hadoop 源代码。这里我们考虑的是 Apache Hadoop 1.0.3,而最新版本是 1.1.x。
// Locate to Hadoop installation directory $ cd /usr/local // Extract the tar file of Hadoop distribution $ sudo tar xzf hadoop-1.0.3.tar.gz // To move Hadoop resources to hadoop folder $ sudo mv hadoop-1.0.3 hadoop // Make user-hduser from group-hadoop as owner of hadoop directory $ sudo chown -R hduser:hadoop hadoop -
将
$JAVA_HOME和$HADOOP_HOME变量添加到 Hadoop 系统用户的.bashrc文件中,更新后的.bashrc文件如下所示:// Setting the environment variables for running Java and Hadoop commands export HADOOP_HOME=/usr/local/hadoop export JAVA_HOME=/usr/lib/jvm/java-6-sun // alias for Hadoop commands unalias fs &> /dev/null alias fs="hadoop fs" unalias hls &> /dev/null aliashls="fs -ls" // Defining the function for compressing the MapReduce job output by lzop command lzohead () { hadoopfs -cat $1 | lzop -dc | head -1000 | less } // Adding Hadoop_HoME variable to PATH export PATH=$PATH:$HADOOP_HOME/bin -
使用
conf/*-site.xml格式更新 Hadoop 配置文件。
最终,三个文件将如下所示:
-
conf/core-site.xml:<property> <name>hadoop.tmp.dir</name> <value>/app/hadoop/tmp</value> <description>A base for other temporary directories.</description> </property> <property> <name>fs.default.name</name> <value>hdfs://localhost:54310</value> <description>The name of the default filesystem. A URI whose scheme and authority determine the FileSystem implementation. The uri's scheme determines the config property (fs.SCHEME.impl) naming theFileSystem implementation class. The uri's authority is used to determine the host, port, etc. for a filesystem.</description> </property> -
conf/mapred-site.xml:<property> <name>mapred.job.tracker</name> <value>localhost:54311</value> <description>The host and port that the MapReduce job tracker runs at. If "local", then jobs are run in-process as a single map and reduce task. </description> </property> -
conf/hdfs-site.xml:<property> <name>dfs.replication</name> <value>1</value> <description>Default block replication. The actual number of replications can be specified when the file is created. The default is used if replication is not specified in create time. </description>
编辑完这些配置文件后,我们需要在 Hadoop 集群或节点之间设置分布式文件系统。
-
通过以下命令格式化 Hadoop 分布式文件系统(HDFS):
hduser@ubuntu:~$ /usr/local/hadoop/bin/hadoopnamenode -format -
使用以下命令行启动您的单节点集群:
hduser@ubuntu:~$ /usr/local/hadoop/bin/start-all.sh
提示
下载示例代码
您可以从您的账户在 www.packtpub.com 下载所有您购买的 Packt 图书的示例代码文件。如果您在其他地方购买了此书,您可以访问 www.packtpub.com/support 并注册,将文件直接通过电子邮件发送给您。
在 Linux 上安装 Hadoop,Ubuntu 版本(多节点集群)
我们已经学习了如何在单节点集群上安装 Hadoop。现在我们将看到如何在多节点集群上安装 Hadoop(完全分布式模式)。
为此,我们需要多个节点配置一个单节点 Hadoop 集群。要在多节点上安装 Hadoop,我们需要按照上一节中描述的方式先配置好单节点 Hadoop 集群。
在安装完单节点 Hadoop 集群后,我们需要执行以下步骤:
-
在网络配置阶段,我们将使用两个节点来设置完整的分布式 Hadoop 模式。为了彼此通信,这些节点需要在软件和硬件配置上处于同一网络中。
-
在这两个节点中,一个将被视为主节点,另一个将被视为从节点。因此,为了执行 Hadoop 操作,主节点需要连接到从节点。我们将在主机上输入
192.168.0.1,在从机上输入192.168.0.2。 -
更新两个节点中的
/etc/hosts目录。它将显示为192.168.0.1 master和192.168.0.2 slave。提示
你可以像我们在单节点集群设置中做的那样进行安全外壳(SSH)设置。欲了解更多详情,请访问
www.michael-noll.com。 -
更新
conf/*-site.xml:我们必须在所有节点中更改这些配置文件。-
conf/core-site.xml和conf/mapred-site.xml:在单节点设置中,我们已经更新了这些文件。所以现在我们只需要将值标签中的localhost替换为master。 -
conf/hdfs-site.xml:在单节点设置中,我们将dfs.replication的值设置为1。现在我们需要将其更新为2。
-
-
在格式化 HDFS 阶段,在我们启动多节点集群之前,我们需要使用以下命令格式化 HDFS(从主节点执行):
bin/hadoop namenode -format
现在,我们已经完成了安装多节点 Hadoop 集群的所有步骤。要启动 Hadoop 集群,我们需要遵循以下步骤:
-
启动 HDFS 守护进程:
hduser@master:/usr/local/hadoop$ bin/start-dfs.sh -
启动 MapReduce 守护进程:
hduser@master:/usr/local/hadoop$ bin/start-mapred.sh -
或者,我们可以通过一个命令启动所有守护进程:
hduser@master:/usr/local/hadoop$ bin/start-all.sh -
要停止所有这些守护进程,执行:
hduser@master:/usr/local/hadoop$ bin/stop-all.sh
这些安装步骤是受启发于 Michael Noll 的博客(www.michael-noll.com)的,他是位于欧洲瑞士的研究员和软件工程师。他在 VeriSign 担任 Apache Hadoop 堆栈的大规模计算基础设施技术负责人。
现在,Hadoop 集群已经在你的机器上设置完成。要在单节点或多节点上安装相同的 Hadoop 集群并扩展 Hadoop 组件,可以尝试使用 Cloudera 工具。
在 Ubuntu 上安装 Cloudera Hadoop
Cloudera Hadoop (CDH) 是 Cloudera 的开源发行版,旨在面向企业级部署 Hadoop 技术。Cloudera 也是 Apache 软件基金会的赞助商。CDH 提供两个版本:CDH3 和 CDH4. 要安装其中之一,您必须使用带有 10.04 LTS 或 12.04 LTS 的 Ubuntu(此外,您还可以尝试 CentOS、Debian 和 Red Hat 系统)。如果您在多台计算机的集群上安装 Hadoop,Cloudera 管理器将使安装过程变得更加容易,它提供基于 GUI 的 Hadoop 和其组件的安装。强烈建议在大型集群中使用该工具。
我们需要满足以下先决条件:
-
配置 SSH
-
操作系统应符合以下标准:
-
Ubuntu 10.04 LTS 或 12.04 LTS(64 位)
-
Red Hat Enterprise Linux 5 或 6
-
CentOS 5 或 6
-
Oracle Enterprise Linux 5
-
SUSE Linux Enterprise Server 11(SP1 或 Lasso)
-
Debian 6.0
-
安装步骤如下:
-
下载并运行 Cloudera 管理器安装程序:要初始化 Cloudera 管理器安装过程,首先需要从 Cloudera 网站的下载区下载
cloudera-manager-installer.bin文件。下载后,将其存储在集群中,以便所有节点都可以访问此文件。允许用户执行cloudera-manager-installer.bin文件。运行以下命令开始执行。$ sudo ./cloudera-manager-installer.bin -
阅读 Cloudera 管理器 Readme 文件,然后点击 下一步。
-
启动 Cloudera 管理器管理员控制台:Cloudera 管理器管理员控制台允许您使用 Cloudera 管理器在集群上安装、管理和监控 Hadoop。接受 Cloudera 服务提供商的许可后,您需要通过在地址栏中输入
http://localhost:7180来转到本地网页浏览器。您还可以使用以下任何浏览器:-
Firefox 11 或更高版本
-
Google Chrome
-
Internet Explorer
-
Safari
-
-
使用
admin作为用户名和密码登录 Cloudera 管理器控制台。以后可以根据需要更改密码。 -
使用 Cloudera 管理器通过浏览器进行自动化的 CDH3 安装和配置:此步骤将从 Cloudera 向您的计算机安装大部分所需的 Cloudera Hadoop 包。步骤如下:
-
安装并验证您的 Cloudera 管理器许可证密钥文件(如果您选择了完整版本的软件)。
-
为 CDH 集群安装指定主机名或 IP 地址范围。
-
使用 SSH 连接到每个主机。
-
安装 Java 开发工具包 (JDK)(如果尚未安装),Cloudera 管理器代理,以及 CDH3 或 CDH4 在每个集群主机上。
-
在每个节点上配置 Hadoop 并启动 Hadoop 服务。
-
-
运行向导并使用 Cloudera 管理器后,您应该尽快更改默认管理员密码。更改管理员密码,请按照以下步骤操作:
-
点击带有齿轮标志的图标,显示管理页面。
-
打开 密码 标签。
-
输入新密码两次,然后单击Update。
-
-
测试 Cloudera Hadoop 的安装:您可以通过登录 Cloudera 管理器管理控制台并单击Services选项卡来检查您集群上的 Cloudera 管理器安装。您应该看到类似下面这样的屏幕截图:
![在 Ubuntu 上安装 Cloudera Hadoop]()
Cloudera 管理器管理控制台
-
您还可以单击每个服务以查看更详细的信息。例如,如果您单击hdfs1链接,您可能会看到类似下面这样的屏幕截图:
![在 Ubuntu 上安装 Cloudera Hadoop]()
Cloudera 管理器管理控制台——HDFS 服务
提示
要避免这些安装步骤,请使用预配置的 Amazon Elastic MapReduce 和 MapReduce 实例。
如果你想在 Windows 上使用 Hadoop,请尝试由 Hortonworks 提供的 HDP 工具。这是完全开源的、企业级的 Hadoop 发行版。你可以在
hortonworks.com/download/下载 HDP 工具。
理解 Hadoop 的特性
Hadoop 专为两个核心概念而设计:HDFS 和 MapReduce。两者都与分布式计算相关。MapReduce 被认为是 Hadoop 的核心,它执行分布式数据上的并行处理。
让我们看看 Hadoop 的特性的更多细节:
-
HDFS
-
MapReduce
理解 HDFS
HDFS 是 Hadoop 自带的机架感知文件系统,是 Hadoop 的基于 UNIX 的数据存储层。HDFS 源自于 Google 文件系统的概念。Hadoop 的一个重要特性是数据和计算的分区跨多个(数千个)主机,并在靠近其数据的地方并行执行应用程序计算。在 HDFS 上,数据文件被复制为集群中的块序列。通过简单添加商品服务器,Hadoop 集群可以扩展计算能力、存储能力和 I/O 带宽。HDFS 可以通过多种不同的方式从应用程序访问。本地,HDFS 为应用程序提供了一个 Java API。
Yahoo!的 Hadoop 集群覆盖 40,000 台服务器,存储 40PB 的应用程序数据,其中最大的 Hadoop 集群为 4,000 台服务器。此外,全球还有 100 多个组织使用 Hadoop。
理解 HDFS 的特性
现在让我们来看看 HDFS 的特性:
-
容错
-
使用商品硬件运行
-
能够处理大型数据集
-
主从范式
-
只有一次文件访问权限
理解 MapReduce
MapReduce 是一种用于处理分布在大型集群上的大型数据集的编程模型。MapReduce 是 Hadoop 的核心。其编程范式允许在配置有 Hadoop 集群的数千台服务器上执行大规模数据处理。这源自于 Google MapReduce。
Hadoop MapReduce 是一个软件框架,便于编写应用程序,能够在大型集群(数千个节点)的商品硬件上以可靠、容错的方式并行处理大量数据(多 TB 数据集)。该 MapReduce 范式分为两个阶段,Map 和 Reduce,主要处理数据的键值对。Map 和 Reduce 任务在集群中顺序执行;Map 阶段的输出成为 Reduce 阶段的输入。以下是这些阶段的解释:
-
Map 阶段:数据集一旦被划分,就会分配给任务跟踪器以执行 Map 阶段。数据操作将应用于数据,并将映射的键值对作为 Map 阶段的输出。
-
Reduce 阶段:然后,主节点收集所有子问题的答案,并以某种方式将它们组合成最终输出;即最初试图解决的问题的答案。
并行计算的五个常见步骤如下:
-
准备
Map()输入:这将逐行读取输入数据,并为每行发出键值对,或者我们可以根据需求显式地进行更改。- 映射输入:list(k1,v1)
-
运行用户提供的
Map()代码- Map 输出:list(k2,v2)
-
将 Map 输出数据混排到 Reduce 处理器中。同时,将相似的键混排(将其分组),并输入到同一个 reducer 中。
-
运行用户提供的
Reduce()代码:该阶段将运行开发人员设计的自定义 reducer 代码,在混排的数据上运行并发出键值对。-
减少输入:(k2, list(v2))
-
减少输出:(k3, v3)
-
-
产生最终输出:最终,主节点收集所有 reducer 输出,并将其组合后写入文本文件。
提示
有关 Google 文件系统的参考链接可以在
research.google.com/archive/gfs.html找到,Google MapReduce 的链接可以在research.google.com/archive/mapreduce.html找到。
学习 HDFS 和 MapReduce 架构
由于 HDFS 和 MapReduce 被认为是 Hadoop 框架的两个主要特性,我们将重点关注这两者。因此,首先让我们从 HDFS 开始。
理解 HDFS 架构
HDFS 可以呈现为主/从架构。HDFS 的主节点被称为 NameNode,而从节点为 DataNode。NameNode 是一个服务器,管理文件系统的命名空间,并控制客户端对文件的访问(打开、关闭、重命名等)。它将输入数据分割成块,并公告哪个数据块将存储在哪个 DataNode 中。DataNode 是一个从节点,存储分区数据集的副本,并根据请求提供数据。它还执行数据块的创建和删除操作。
HDFS 的内部机制将文件分为一个或多个数据块,这些数据块存储在一组数据节点中。在正常情况下,复制因子为三时,HDFS 策略是将第一份副本放在本地节点上,第二份副本放在同一机架上的不同节点上,第三份副本放入不同机架的不同节点上。由于 HDFS 旨在支持大文件,HDFS 的块大小定义为 64 MB。如果需要,可以增加块大小。
了解 HDFS 组件
HDFS 通过主从架构进行管理,包含以下组件:
-
NameNode:这是 HDFS 系统的主节点。它维护目录、文件,并管理存储在 DataNode 上的数据块。
-
DataNode:这些是部署在每台机器上的从节点,提供实际的存储。它们负责为客户端提供读写数据请求的服务。
-
Secondary NameNode:负责执行定期的检查点。因此,如果 NameNode 发生故障,可以使用由 Secondary NameNode 检查点存储的快照图像进行替换。
了解 MapReduce 架构
MapReduce 也实现了主从架构。经典的 MapReduce 包含作业提交、作业初始化、任务分配、任务执行、进度和状态更新以及作业完成相关活动,这些活动主要由 JobTracker 节点管理,并由 TaskTracker 执行。客户端应用程序向 JobTracker 提交作业。然后,输入数据在集群中分配。JobTracker 计算需要处理的 map 和 reduce 的数量,命令 TaskTracker 开始执行作业。现在,TaskTracker 将资源复制到本地机器并启动 JVM 来执行 map 和 reduce 程序。与此同时,TaskTracker 定期向 JobTracker 发送更新,这可以看作是心跳信号,帮助更新 JobID、作业状态和资源使用情况。
了解 MapReduce 组件
MapReduce 通过主从架构进行管理,包含以下组件:
-
JobTracker:这是 MapReduce 系统的主节点,管理集群中的作业和资源(TaskTracker)。JobTracker 尝试将每个 map 任务调度到与正在处理数据的 TaskTracker 尽可能接近的位置,而 TaskTracker 又运行在与底层数据块相同的 DataNode 上。
-
TaskTracker:这些是部署在每台机器上的从节点,负责按照 JobTracker 的指示运行 map 和 reduce 任务。
通过图示理解 HDFS 和 MapReduce 架构
在此图中,包含了 HDFS 和 MapReduce 的主从组件,其中 NameNode 和 DataNode 来自 HDFS,而 JobTracker 和 TaskTracker 来自 MapReduce 范式。
这两种由主从候选者组成的范式各自有其特定的职责,用于处理 MapReduce 和 HDFS 操作。在下图中,图像分为两个部分:前一部分是 MapReduce 层,后一部分是 HDFS 层。

HDFS 和 MapReduce 架构
Hadoop 是一个顶级的 Apache 项目,是一个非常复杂的 Java 框架。为避免技术复杂性,Hadoop 社区开发了多个 Java 框架,这些框架为 Hadoop 的功能增添了额外的价值。它们被视为 Hadoop 的子项目。在这里,我们将讨论几个可以视为 HDFS 或 MapReduce 抽象的 Hadoop 组件。
理解 Hadoop 子项目
Mahout 是一个流行的数据挖掘库。它采用最流行的数据挖掘可扩展机器学习算法,执行聚类、分类、回归和统计建模,以准备智能应用程序。同时,它是一个可扩展的机器学习库。
Apache Mahout 是在商业友好的 Apache 软件许可下分发的。Apache Mahout 的目标是建立一个充满活力、响应迅速且多样化的社区,促进不仅是项目本身的讨论,还包括潜在的使用案例。
以下是一些使用 Mahout 的公司:
-
Amazon:这是一个购物门户网站,提供个性化推荐服务。
-
AOL:这是一个购物门户网站,用于购物推荐。
-
Drupal:这是一个 PHP 内容管理系统,使用 Mahout 提供开源基于内容的推荐服务。
-
iOffer:这是一个购物门户网站,使用 Mahout 的频繁模式集挖掘和协同过滤技术向用户推荐商品。
-
LucidWorks Big Data:这是一家流行的分析公司,使用 Mahout 进行聚类、重复文档检测、短语提取和分类。
-
Radoop:提供一个拖拽式界面,用于大数据分析,包括 Mahout 聚类和分类算法。
-
Twitter:这是一个社交网络网站,使用 Mahout 的 潜在狄利克雷分配(LDA)实现进行用户兴趣建模,并在 GitHub 上维护 Mahout 的一个分支。
-
Yahoo!:这是全球最受欢迎的网页服务提供商,使用 Mahout 的频繁模式集挖掘技术用于 Yahoo! Mail。
提示
Hadoop 生态系统的参考链接可以在
www.revelytix.com/?q=content/hadoop-ecosystem找到。
Apache HBase 是一个分布式大数据存储系统,适用于 Hadoop。它允许对大数据进行随机、实时的读写访问。该系统采用了受 Google BigTable 启发创新的列式数据存储模型。
以下是使用 HBase 的公司:
-
Yahoo!:这是全球知名的网页服务提供商,用于近重复文档检测。
-
Twitter:这是一个用于版本控制存储和检索的社交网络网站。
-
Mahalo:这是一个用于相似内容推荐的知识共享服务。
-
NING:这是一个用于实时分析和报告的社交网络服务提供商。
-
StumbleUpon:这是一个通用个性化推荐系统,实时数据存储和数据分析平台。
-
Veoh:这是一个在线多媒体内容共享平台,用于用户档案系统。
提示
对于 Google 大数据,结构化数据的分布式存储系统,请参考链接
research.google.com/archive/bigtable.html。
Hive 是一个基于 Hadoop 的数据仓库框架,由 Facebook 开发。它允许用户使用类似 SQL 的语言(如 HiveQL)进行查询,这些查询会高度抽象为 Hadoop MapReduce。这使得没有 MapReduce 经验的 SQL 程序员也能使用该数据仓库,并使其更容易与商业智能和可视化工具进行集成,以便进行实时查询处理。
Pig 是一个基于 Hadoop 的开源平台,用于通过其自己的类似 SQL 的语言 Pig Latin 来分析大规模数据集。它为海量复杂的数据并行计算提供了简单的操作和编程接口。这也更容易开发,更优化且更具扩展性。Apache Pig 是由 Yahoo! 开发的。目前,Yahoo! 和 Twitter 是主要的 Pig 用户。
对于开发者而言,直接使用 Java API 可能既繁琐又容易出错,而且还限制了 Java 程序员在 Hadoop 编程中灵活性的发挥。因此,Hadoop 提供了两种解决方案,使得数据集管理和数据集分析的 Hadoop 编程变得更容易——这些解决方案是 Pig 和 Hive,这两者经常让人混淆。
Apache Sqoop 提供了一种 Hadoop 数据处理平台,可以快速以一种全新的方式将大量数据从关系型数据库、数据仓库和其他非关系型数据库传输到 Hadoop。Apache Sqoop 是一个用于将数据从关系型数据库导入 Hadoop HDFS,或将数据从 HDFS 导出到关系型数据库的互通数据工具。
它与大多数现代关系型数据库一起工作,如 MySQL、PostgreSQL、Oracle、Microsoft SQL Server 和 IBM DB2,以及企业数据仓库。Sqoop 扩展 API 提供了一种为数据库系统创建新连接器的方法。此外,Sqoop 源代码还提供了一些流行的数据库连接器。为了执行此操作,Sqoop 首先将数据转换为 Hadoop MapReduce,并通过一些数据库模式创建和转换的逻辑来进行处理。
Apache Zookeeper 也是一个 Hadoop 子项目,用于管理 Hadoop、Hive、Pig、HBase、Solr 和其他项目。Zookeeper 是一个开源的分布式应用程序协调服务,设计基于 Fast Paxos 算法的同步、配置和命名服务,如分布式应用程序的维护。在编程中,Zookeeper 的设计采用非常简单的数据模型风格,类似于系统目录树结构。
Zookeeper 分为两部分:服务器和客户端。对于 Zookeeper 服务器集群,只有一个服务器充当领导者,接受并协调所有权限。其余的服务器是主服务器的只读副本。如果领导者服务器宕机,任何其他服务器都可以开始处理所有请求。Zookeeper 客户端连接到 Zookeeper 服务中的服务器。客户端发送请求,接收响应,访问观察事件,并通过与服务器的 TCP 连接发送心跳。
对于分布式应用程序的高性能协调服务,Zookeeper 是一个集中式服务,用于维护配置信息、命名以及提供分布式同步和组服务。所有这些服务以某种形式被分布式应用程序使用。每次实现时,都需要大量的工作来修复不可避免的 bug 和竞态条件。这些服务在应用程序部署时导致管理复杂性。
Apache Solr 是一个开源企业级搜索平台,来自 Apache 许可项目。Apache Solr 具有高度可扩展性,支持分布式搜索和索引复制引擎。这使得构建具有强大文本搜索、分面搜索、实时索引、动态聚类、数据库集成和丰富文档处理的 Web 应用程序成为可能。
Apache Solr 用 Java 编写,作为独立服务器运行,通过类似 REST 的 HTTP/XML 和 JSON API 提供搜索结果。因此,这个 Solr 服务器可以很容易地与用其他编程语言编写的应用程序集成。由于这些特点,这个搜索服务器被 Netflix、AOL、CNET 和 Zappos 等公司使用。
Ambari 是非常特定于 Hortonworks 的。Apache Ambari 是一个基于 Web 的工具,支持 Apache Hadoop 集群的供应、管理和监控。Ambari 处理大部分 Hadoop 组件,包括 HDFS、MapReduce、Hive、Pig、HBase、Zookeeper、Sqoop 和 HCatlog,作为集中管理。
此外,Ambari 能够基于 Kerberos 身份验证协议在 Hadoop 集群上安装安全性。同时,它还为用户提供基于角色的用户身份验证、授权和审计功能,帮助用户管理集成的 LDAP 和 Active Directory。
总结
在本章中,我们学习了什么是 R、Hadoop 及其特点,并了解了如何安装它们,然后才能使用 R 和 Hadoop 进行数据集分析。在下一章中,我们将学习什么是 MapReduce,以及如何使用 Apache Hadoop 开发 MapReduce 程序。
第二章:编写 Hadoop MapReduce 程序
在上一章中,我们学习了如何设置 R 和 Hadoop 开发环境。由于我们有兴趣执行大数据分析,因此我们需要学习 Hadoop 以便使用 Hadoop MapReduce 执行操作。在本章中,我们将讨论什么是 MapReduce,为什么它是必要的,如何通过 Apache Hadoop 开发 MapReduce 程序,以及更多内容。
在本章中,我们将涵盖:
-
理解 MapReduce 的基本概念
-
介绍 Hadoop MapReduce
-
理解 Hadoop MapReduce 基础
-
编写一个 Hadoop MapReduce 示例
-
理解多种可能的 MapReduce 定义,以解决业务问题
-
学习在 R 中编写 Hadoop MapReduce 的不同方式
理解 MapReduce 基础
如果没有集群或使用消息传递接口(MPI),理解 MapReduce 基础可能是一个长期的解决方案。然而,更现实的使用场景是当数据无法存储在一块磁盘上,但可以存储在分布式文件系统(DFS)中,或者已经存储在 Hadoop 相关软件上。
此外,MapReduce 是一种分布式编程模型,但它并不是唯一一种支持分布式的编程模型。描述其他编程模型可能会有所启发,例如 MPI 和批量同步并行(BSP)。使用 R 等工具和若干机器学习技术处理大数据需要高配置的机器,但这并不是永久解决方案。因此,分布式处理是处理这些数据的关键。这种分布式计算可以通过 MapReduce 编程模型来实现。
MapReduce 是解决大数据问题的答案。从逻辑上讲,要处理数据,我们需要并行处理,这意味着需要大规模计算;这种处理方式可以通过将计算机集群进行聚集或提高单机配置来实现。使用计算机集群是处理大规模数据的理想方式。
在我们深入讨论并行处理中的 MapReduce 之前,我们将讨论 Google MapReduce 研究以及Jeffrey Dean和Sanjay Ghemawat在 2004 年撰写的白皮书。它们将 MapReduce 介绍为一种简化的大规模集群数据处理软件。MapReduce 实现运行在由普通硬件组成的大型集群上。这种数据处理平台使得程序员可以更容易地执行各种操作。系统负责处理输入数据、将数据分配到计算机网络中、并行处理这些数据,最后将输出结果合并成一个文件,供之后聚合。这对于成本控制非常有帮助,而且也是一种节省时间的系统,适用于在集群上处理大型数据集。此外,它能高效地利用计算机资源来处理大量数据进行分析。Google 已获得 MapReduce 的专利。
对于 MapReduce,程序员只需要将应用程序设计/迁移为两个阶段:Map 和 Reduce。他们只需要设计 Map 函数,用于处理键值对并生成一组中间的键值对,然后设计 Reduce 函数,用于合并所有的中间键。Map 和 Reduce 函数共同维护 MapReduce 的工作流。Reduce 函数将在 Map 输出可用后开始执行代码。
它们的执行顺序如下所示:

MapReduce 假设 Map 是独立的,并且会并行执行它们。MapReduce 算法的关键是,如果每个 Map 和 Reduce 都与网络中其他正在进行的 Map 和 Reduce 独立,那么操作将在不同的键和数据列表上并行运行。
分布式文件系统将数据的多个副本分布到不同的机器上。这提供了可靠性和容错能力。如果一台机器上的文件副本崩溃,另一台复制的数据源将提供相同的数据。
MapReduce 守护进程的主节点将负责 MapReduce 作业的所有职责,如作业的执行、Mappers、Reducers、Combiners 和 Partitioners 的调度、监控个别作业任务的成功与失败,最后完成批处理作业。
Apache Hadoop 通过在存储在 Hadoop 分布式文件系统上的数据附近运行 Hadoop MapReduce 作业,以并行方式处理分布式数据。
使用 MapReduce 的公司包括:
-
Amazon:这是一个在线电子商务和云服务提供商,专注于大数据分析
-
eBay:这是一个电子商务门户网站,用于根据描述查找商品
-
Google:这是一个网页搜索引擎,用于查找与特定主题相关的页面
-
LinkedIn:这是一个专业的社交网站,用于大数据存储和生成个性化推荐
-
Trovit:这是一个垂直搜索引擎,用于查找与给定描述匹配的工作
-
Twitter:这是一个社交网站,用于查找消息
除了这些,还有许多其他品牌正在使用 Hadoop 进行大数据分析。
引入 Hadoop MapReduce
基本上,MapReduce 模型可以用多种语言实现,但除了这些,Hadoop MapReduce 是一个流行的 Java 框架,便于编写应用程序。它以可靠和容错的方式在大型集群(成千上万的节点)上的商品硬件上并行处理大量数据(多 TB 数据集)。这个 MapReduce 范式分为两个阶段:Map 和 Reduce,主要处理数据的键值对。Map 和 Reduce 任务在集群中顺序运行,Map 阶段的输出成为 Reduce 阶段的输入。
MapReduce 中的所有数据输入元素都无法更新。如果映射任务的输入 (key, value) 对发生更改,将不会反映在输入文件中。Mapper 输出将通过管道传输到适当的 Reducer,并按键属性分组作为输入。这个顺序的数据处理将通过 Hadoop MapReduce 算法和 Hadoop 集群以并行方式执行。
MapReduce 程序将以列表格式呈现的输入数据集转换为同样以列表格式呈现的输出数据。这一逻辑列表转换过程通常在 Map 阶段和 Reduce 阶段重复两次。我们还可以通过固定 Mapper 和 Reducer 的数量来处理这些重复。在接下来的部分中,将根据旧的 MapReduce API 描述 MapReduce 概念。
列出 Hadoop MapReduce 实体
以下是负责在大数据上执行分析的 Hadoop 组件:
-
Client:这是用来初始化任务的。
-
JobTracker:这是用来监控任务的。
-
TaskTracker:这是执行任务的。
-
HDFS:这是用来存储输入和输出数据的。
理解 Hadoop MapReduce 场景
Hadoop MapReduce 数据处理的四个主要阶段如下:
-
将数据加载到 HDFS 中
-
执行 Map 阶段
-
洗牌和排序
-
执行 Reduce 阶段
将数据加载到 HDFS 中
输入数据集需要上传到 Hadoop 目录,以便 MapReduce 节点可以使用它。然后,Hadoop 分布式文件系统(HDFS)将把输入数据集分割成数据块,并将它们存储到集群中的 DataNodes,同时确保为容错设置复制因子。所有的数据块将由 TaskTracker 以并行方式处理 Map 和 Reduce 任务。
此外,还有一些替代方法可以通过 Hadoop 组件将数据集获取到 HDFS 中:
-
Sqoop:这是一个开源工具,旨在高效地在 Apache Hadoop 和结构化关系型数据库之间传输大量数据。假设你的应用已经配置了 MySQL 数据库,并且你想用相同的数据进行数据分析,建议使用 Sqoop 将数据集导入到 HDFS。此外,数据分析过程完成后,输出可以导出到 MySQL 数据库中。
-
Flume:这是一个分布式、可靠且可用的服务,用于高效地收集、汇总和传输大量日志数据到 HDFS。Flume 能够从大多数源读取数据,例如日志文件、系统日志和 Unix 进程的标准输出。
使用前面的数据收集和移动框架,可以让 MapReduce 应用程序的数据传输过程变得非常简单,便于数据分析。
执行 Map 阶段
执行客户端应用程序启动 Hadoop MapReduce 进程。然后 Map 阶段复制作业资源(未解压的类文件)并将其存储到 HDFS,并请求 JobTracker 执行作业。JobTracker 初始化作业,检索输入,拆分信息,并为每个作业创建一个 Map 任务。
JobTracker 将调用 TaskTracker 运行分配的输入数据子集的 Map 任务。Map 任务将此输入拆分数据作为输入 (key, value) 对提供给 Mapper 方法,然后生成中间 (key, value) 对。对于每个输入 (key, value) 对至少会有一个输出。

映射输入列表的各个元素
生成的 (key, value) 对列表是这样生成的,即键属性将被多次重复使用。因此,对于在 MapReduce 中聚合值的 Reducer,它的键属性将被重新使用。就格式而言,Mapper 输出格式的值和 Reducer 输入的值必须相同。
在完成此 Map 操作后,TaskTracker 将在其缓冲存储和本地磁盘空间中保留结果(如果输出数据大小超过阈值)。
例如,假设我们有一个将输入文本转换为小写的 Map 函数。这将把输入字符串列表转换为小写字符串列表。
提示
键和值:在 MapReduce 中,每个值都有其被视为键的标识符。由 Mapper 接收的键值对依赖于作业配置文件中指定的输入数据类型。
分组和排序
要优化 MapReduce 程序,这个中间阶段非常重要。
一旦 Mapper 阶段的 Map 输出可用,此中间阶段将自动调用。在 Map 阶段完成后,所有发出的中间 (key, value) 对将由 Mapper 侧的分区器进行分区,只要分区器存在。分区器的输出将根据 Mapper 侧的键属性进行排序。排序操作的输出存储在 Mapper 节点 TaskTracker 上可用的缓冲内存中。
Combiner 通常就是 Reducer 本身。因此,通过压缩,它不是 Gzip 或类似的压缩,而是 Map 输出数据的 Reducer 节点。由 Combiner 返回的数据然后被分组并发送到减少节点。为了加速 Mapper 输出到 TaskTracker 的 Reducer 插槽的数据传输,需要使用 Combiner 函数压缩该输出。默认情况下,Mapper 输出将存储到缓冲内存中,如果输出大小大于阈值,则会存储到本地磁盘。这些输出数据可通过 超文本传输协议 (HTTP) 访问。
减少阶段的执行
一旦 Mapper 输出可用,Reducer 节点上的 TaskTracker 将检索可用的分区 Map 输出数据,这些数据将被分组并合并成一个大文件,然后分配给一个包含 Reducer 方法的进程。最后,在数据提供给 Reducer 方法之前,会对其进行排序。
Reducer 方法接收来自输入 (key, list (value)) 的输入值列表,并根据自定义逻辑对它们进行聚合,生成输出 (key, value) 对。

将输入值减少为一个聚合值作为输出
Reduce 阶段的 Reducer 方法的输出将根据 MapReduce 作业配置类指定的格式直接写入 HDFS。
理解 MapReduce 的局限性
让我们看看 Hadoop MapReduce 的一些局限性:
-
MapReduce 框架对于非简单的转换逻辑(例如实时流处理、图处理和消息传递)来说,众所周知很难使用。
-
在分布式、未索引的数据上进行数据查询比在使用已索引数据创建的数据库中要低效。然而,如果为数据生成了索引,在数据删除或添加时需要维护该索引。
-
我们无法将 Reduce 任务并行化到 Map 任务上以减少整体处理时间,因为 Reduce 任务只有在 Map 任务的输出可用时才能开始。(Reducer 的输入完全依赖于 Mapper 的输出。)此外,我们无法控制 Map 和 Reduce 任务执行的顺序。但有时,根据应用逻辑,我们可以在 Map 任务完成后,数据收集开始时,配置一个 Reduce 任务的慢启动。
-
长时间运行的 Reduce 任务无法完成,原因是资源利用率低,可能是因为 Reduce 任务花费太多时间导致失败,或者没有其他 Reduce 插槽可供重新调度(这可以通过 YARN 来解决)。
理解 Hadoop 解决问题的能力
由于本书面向分析师,因此提供一些分析示例可能是相关的;例如,如果读者遇到与之前描述的类似问题,Hadoop 可能会有所帮助。Hadoop 不是解决所有大数据问题的万能方案;它只是当需要将大量数据分割成小块并分布到服务器上进行并行处理时,使用的一种不错的技术。这可以节省时间和在大数据集上执行分析的成本。
如果我们能够为问题设计 Map 和 Reduce 阶段,那么就可以使用 MapReduce 来解决它。通常,Hadoop 提供计算能力来处理不适合机器内存的数据。(R 用户在处理大数据时,通常会遇到以下错误消息:无法分配大小为 2.5 GB 的向量。)
理解 Hadoop 编程中使用的不同 Java 概念
有一些经典的 Java 概念,使得 Hadoop 更具互动性。它们如下:
-
远程过程调用:这是一种进程间通信方式,允许计算机程序在另一个地址空间(通常是在共享网络上的另一台计算机)执行子程序或过程,而不需要程序员明确编写远程交互的详细代码。也就是说,程序员编写的代码基本相同,无论子程序是本地执行的还是远程执行的。
-
序列化/反序列化:通过序列化,Java 虚拟机(JVM)可以将对象的状态写入某个流中,这样我们就可以基本上读取所有成员并将其状态写入流、磁盘等。默认机制采用二进制格式,因此它比文本格式更加紧凑。通过这种方式,计算机可以通过网络发送数据。反序列化则相反,用于接收网络中的数据对象。
-
Java 泛型:这使得类型或方法能够在不同类型的对象上操作,同时提供编译时类型安全,使得 Java 成为一种完全静态类型的语言。
-
Java 集合:该框架是一组用于处理各种类型数据集合的类和接口,能够使用单一的 Java 对象进行操作。
-
Java 并发:该设计用于支持并发编程,所有执行都发生在线程的上下文中。它主要用于将计算过程作为一组线程实现,在单个操作系统进程中执行。
-
普通旧 Java 对象(POJO):这些实际上是普通的 JavaBeans。POJO 被临时用来设置和获取数据对象的值。
理解 Hadoop MapReduce 基本原理
为了正确理解 Hadoop MapReduce 的基本原理,我们将:
-
理解 MapReduce 对象
-
学习如何决定 MapReduce 中的 Map 数量
-
学习如何决定 MapReduce 中的 Reduce 数量
-
理解 MapReduce 数据流
-
更深入地了解 Hadoop MapReduce 的术语
理解 MapReduce 对象
正如我们所知,Hadoop 中的 MapReduce 操作主要由三个对象执行:Mapper、Reducer 和 Driver。
-
Mapper:这是为 MapReduce 的 Map 阶段设计的,它通过携带输入文件并将其拆分成若干块来启动 MapReduce 操作。对于每一块,它会生成一个键值对作为输出值。
-
Reducer:这是为 MapReduce 作业的 Reduce 阶段设计的;它接受来自 Mapper 输出的按键分组的数据,通过聚合逻辑进行处理,并输出该组数据的
(key, value)键值对。 -
驱动程序:这是驱动 MapReduce 过程的主文件。它在从客户端应用程序获取请求和参数后启动 MapReduce 任务的执行。驱动程序负责构建作业的配置并将其提交到 Hadoop 集群。驱动程序代码包含接受命令行参数的
main()方法。此程序将接受 Hadoop MapReduce 作业的输入和输出目录。驱动程序是定义作业配置细节的主要文件,如作业名称、作业输入格式、作业输出格式以及 Mapper、Combiner、Partitioner 和 Reducer 类。通过调用驱动程序类的main()函数来初始化 MapReduce。
并非每个问题都可以用单个 Map 和单个 Reduce 程序解决,但更少的问题无法用单个 Map 和单个 Reduce 任务解决。有时,还需要设计具有多个 Map 和 Reduce 任务的 MapReduce 作业。当需要在单个作业中执行数据操作(如数据提取、数据清洗和数据合并)时,可以设计这种类型的作业。通过为单个作业编写多个 Mapper 和 Reducer 任务,可以解决许多问题。在多个 Map 和 Reduce 任务的情况下,将依次调用 Map1 后跟 Reduce1,Map2 后跟 Reduce2 等 MapReduce 步骤。
当我们需要编写具有多个 Map 和 Reduce 任务的 MapReduce 作业时,我们必须编写多个 MapReduce 应用程序驱动程序来依次运行它们。
在提交 MapReduce 作业时,我们可以提供一定数量的 Map 任务,根据 Mapper 输入和 Hadoop 集群容量创建一定数量的 Reducers。同时,注意设置 Mappers 和 Reducers 的数量并非强制要求。
决定 MapReduce 中的 Maps 数量
Map 数量通常由输入数据的大小和由 HDFS 文件/数据划分计算的数据块大小定义。因此,如果我们有一个 5 TB 的 HDFS 数据文件和 128 MB 的块大小,文件中将有 40,960 个 Map。但有时,由于推测执行,创建的 Mapper 数量将超过此计数。当输入是文件时,这是真实的,尽管它完全取决于InputFormat类。
在 Hadoop MapReduce 处理中,当分配的 Mapper 或 Reducer 需要较长时间完成时,作业结果会有延迟。如果要避免这种情况,在 Hadoop 中的推测执行可以在不同节点上运行同一 Map 或 Reduce 任务的多个副本,并可以使用首次完成节点的结果。通过 Hadoop API 的setNumMapTasks(int)方法,我们可以了解 Mapper 的数量。
决定 MapReduce 中 Reducers 的数量
Reducer 的数量是根据 Mapper 的输入创建的。然而,如果你在 MapReduce 中硬编码 Reducer 的数量,集群中有多少节点也无关紧要。它将按照配置中指定的方式执行。
此外,我们可以在运行时通过命令行 -D mapred.reduce.tasks 设置 Reducer 的数量,并指定需要的数量。程序上也可以通过 conf.setNumReduceTasks(int) 设置。
理解 MapReduce 数据流
现在我们已经了解了构成基本 MapReduce 作业所需的组件,我们将从更高层次区分每个部分如何协同工作。从下面的图示中,我们将理解 Hadoop 集群中多个节点的 MapReduce 数据流:

MapReduce 数据流
Hadoop MapReduce 可用的两种 API 是:新版本(Hadoop 1.x 和 2.x)和旧版本 Hadoop(0.20)。YARN 是下一代 Hadoop MapReduce,是为 Hadoop 资源管理发布的新 Apache Hadoop 子项目。
Hadoop 数据处理包括多个任务,帮助从输入数据集中获得最终输出。这些任务如下:
-
在 HDFS 中预加载数据。
-
通过调用 Driver 来运行 MapReduce。
-
由 Mappers 读取输入数据,这会导致数据的拆分,执行 Mapper 自定义逻辑,并生成中间的键值对。
-
执行 Combiner 和 shuffle 阶段,以优化整体 Hadoop MapReduce 过程。
-
对中间键值对进行排序,并将其提供给 Reduce 阶段。然后执行 Reduce 阶段。Reducers 根据 Reducer 逻辑聚合这些分区的键值对。
-
最终的输出数据存储在 HDFS 中。
在这里,可以为以下几种数据操作定义 Map 和 Reduce 任务:
-
数据提取
-
数据加载
-
数据分割
-
数据清洗
-
数据转化
-
数据集成
我们将在本章的下一部分更详细地探讨 MapReduce 任务。
更详细地了解 Hadoop MapReduce 术语
在本节中,我们将进一步了解 Hadoop MapReduce 数据流,并介绍多个 MapReduce 术语及其 Java 类细节。在前面一节的 MapReduce 数据流图中,多个节点通过网络连接进行分布式处理,基于 Hadoop 设置。Map 和 Reduce 阶段的随之属性在获取最终输出时起着重要作用。
Map 阶段的属性如下:
-
InputFiles术语指的是已经创建/提取并存储在 HDFS 中,供业务分析使用的输入原始数据集。这些输入文件非常大,并且有多种类型。 -
InputFormat是一个 Java 类,用于通过获取每行的偏移量和内容来处理输入文件。它定义了如何拆分和读取输入数据文件。我们可以设置多个输入类型,例如TextInputFormat、KeyValueInputFormat和SequenceFileInputFormat,这些输入格式与 Map 和 Reduce 阶段相关。 -
InputSplits类用于设置数据分割的大小。 -
RecordReader是一个 Java 类,提供多个方法,通过迭代数据分割来检索键和值。它还包括其他方法,用于获取当前进度的状态。 -
为 Map 阶段创建
Mapper实例。Mapper类接受输入的(key, value)对(由 RecordReader 生成),并通过在Map()方法中执行用户定义的代码生成一个中间的(key, value)对。Map()方法主要接受两个输入参数:key 和 value;其余的参数是OutputCollector和Reporter。它们将提供中间的键值对,以供作业的 Reduce 阶段使用。Reporter会定期向 JobTracker 提供当前作业的状态。JobTracker 会在作业结束时汇总这些状态,供后续检索。
Reduce 阶段的属性如下:
-
在完成 Map 阶段后,生成的中间
(key, value)对会根据hash函数中的键属性相似性进行分区。因此,每个 Map 任务可能会将(key, value)对发射到不同的分区;对于相同的键,所有值总是一起被 Reducer 处理,而不管它们来自哪个 Mapper。这个分区和洗牌操作将在 Map 阶段完成后由 MapReduce 作业自动执行,无需单独调用。此外,我们可以根据 MapReduce 作业的要求显式覆盖它们的逻辑代码。 -
在完成分区和洗牌操作并在初始化 Reduce 任务之前,Hadoop MapReduce 作业会根据键属性值对中间
(key, value)对进行排序。 -
为 Reduce 阶段创建
Reduce实例。它是一个用户提供的代码段,用于执行 Reduce 任务。Reducer类的Reduce()方法主要接受两个参数,以及OutputCollector和Reporter,与Map()函数相同。它们是OutputCollector和Reporter对象。Map 和 Reduce 中的OutputCollector功能相同,但在 Reduce 阶段,OutputCollector将输出提供给下一个 Map 阶段(在多个 Map 和 Reduce 作业组合的情况下),或者根据需求将其报告为作业的最终输出。此外,Reporter会定期向 JobTracker 报告当前任务的状态。 -
最后,在
OutputFormat中,生成的输出(键,值)对被提供给OutputCollector参数,然后写入OutputFiles,该过程由OutputFormat控制。它控制OutputFiles格式的设置,格式的选择由 MapReduce Driver 定义。格式将从TextOutputFormat、SequenceFileOutputFileFormat或NullOutputFormat中选择。 -
RecordWriter是OutputFormat使用的工厂,用于以适当的格式写入输出数据。 -
输出文件是
RecordWriter在 MapReduce 作业完成后写入 HDFS 的输出数据。
为了高效地运行此 MapReduce 作业,我们需要了解一些 Hadoop Shell 命令以执行管理任务。请参考下表:
| Shell 命令 | 用法和代码示例 |
|---|
|
cat
| 将源路径复制到stdout:
Hadoop fs -cat URI [URI …]
|
|
chmod
| 更改文件的权限:
Hadoop fs -chmod [-R] <MODE[,MODE]... | OCTALMODE> URI [URI …]
|
|
copyFromLocal
| 将文件从本地存储复制到 HDFS:
Hadoop fs –copyFromLocal<localsrc> URI
|
|
copyToLocal
| 将文件从 HDFS 复制到本地存储:
Hadoop fs -copyToLocal [-ignorecrc] [-crc] URI <localdst>
|
|
cp
| 将文件从源路径复制到目标路径(HDFS):
Hadoop fs -cp URI [URI …] <dest>
|
|
du
| 显示文件的总长度:
Hadoop fs -du URI [URI …]
|
|
dus
| 显示文件长度的汇总信息:
Hadoop fs -dus<args>
|
|
get
| 将文件复制到本地文件系统:
Hadoop fs -get [-ignorecrc] [-crc] <src><localdst>
|
|
ls
| 在 HDFS 中列出当前目录的所有文件:
Hadoop fs –ls<args>
|
|
mkdir
| 在 HDFS 中创建目录:
Hadoop fs –mkdir<paths>
|
|
lv
| 将文件从源路径移动到目标路径:
Hadoop fs -mv URI [URI …] <dest>
|
|
rmr
| 从当前目录中删除文件:
Hadoop fs -rmr URI [URI …]
|
|
setrep
| 更改文件的副本因子:
Hadoop fs -setrep [-R] <path>
|
|
tail
| 将文件的最后一个千字节显示到stdout:
Hadoop fs -tail [-f] URI
|
编写一个 Hadoop MapReduce 示例
现在,我们将通过学习一个非常常见且简单的单词计数示例来继续深入了解 MapReduce。此示例的目标是计算每个单词在提供的文档中出现的次数。这些文档可以视为 MapReduce 的输入文件。
在此示例中,我们已经有了一组文本文件——我们想要识别文件中所有唯一单词的出现频率。我们将通过设计 Hadoop MapReduce 阶段来实现这一点。
在本节中,我们将更多地了解使用 Hadoop MapReduce 的旧 API 进行编程。在这里,我们假设读者已经按照第一章中的说明设置好了 Hadoop 环境,准备使用 R 和 Hadoop。另外,请记住,我们在此不会使用 R 来计数单词;这里只使用 Hadoop。
基本上,Hadoop MapReduce 有三个主要对象:Mapper、Reducer 和 Driver。它们可以通过三个 Java 类进行开发;分别是Map类、Reduce类和Driver类,其中Map类表示 Map 阶段,Reducer类表示 Reduce 阶段,Driver类表示包含main()方法以初始化 Hadoop MapReduce 程序的类。
在前一节的 Hadoop MapReduce 基础中,我们已经讨论了什么是 Mapper、Reducer 和 Driver。现在,我们将学习如何在 Java 中定义它们并进行编程。在接下来的章节中,我们将学习如何将 R 和 Hadoop 结合使用做更多的事情。
提示
有许多语言和框架用于构建 MapReduce,但每种语言或框架都有其独特的优势。有多个因素可以通过修改来提高 MapReduce 的延迟。请参考 Cloudera 的文章 10 MapReduce Tips blog.cloudera.com/blog/2009/05/10-mapreduce-tips/。
为了简化 MapReduce 开发,使用Eclipse并配置Maven,该工具支持旧版 MapReduce API。
了解运行 MapReduce 作业的步骤
让我们来看一下运行 MapReduce 作业的步骤:
-
在准备 Java 类的初始步骤中,我们需要您根据我们的业务问题定义开发一个 Hadoop MapReduce 程序。在这个示例中,我们考虑了一个词频统计问题。因此,我们开发了三个用于 MapReduce 程序的 Java 类,它们分别是
Map.java、Reduce.java和WordCount.java,用于计算提供的文本文件中单词的频率。-
Map.java:这是用于词频统计 Mapper 的 Map 类。// Defining package of the class package com.PACKT.chapter1; // Importing java libraries import java.io.*; importjava.util.*; import org.apache.hadoop.io.*; import org.apache.hadoop.mapred.*; // Defining the Map class public class Map extends MapReduceBase implements Mapper<LongWritable, Text, Text, IntWritable>{ //Defining the map method – for processing the data with // problem specific logic public void map(LongWritable key, Text value, OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException { // For breaking the string to tokens and convert them to lowercase StringTokenizer st = new StringTokenizer(value.toString().toLowerCase()); // For every string tokens while(st.hasMoreTokens()) { // Emitting the (key,value) pair with value 1. output.collect(new Text(st.nextToken()), new IntWritable(1)); } } } -
Reduce.java:这是用于词频统计 Reducer 的 Reduce 类。// Defining package of the class package com.PACKT.chapter1; // Importing java libraries import java.io.*; importjava.util.*; import org.apache.hadoop.io.*; importorg.apache.hadoop.mapred.*; // Defining the Reduce class public class Reduce extends MapReduceBase implements Reducer<Text, IntWritable, Text, IntWritable> { // Defining the reduce method for aggregating the //generated output of Map phase public void reduce(Text key, Iterator<IntWritable> values, OutputCollector<Text,IntWritable> output, Reporter reporter) throws IOException { // Setting initial counter value as 0 int count = 0; // For every element with similar key attribute, increment its counter value by adding 1. while(values.hasNext()) { count += values.next().get(); } // Emitting the (key,value) pair output.collect(key, new IntWritable(count)); } } -
WordCount.java:这是 Hadoop MapReduce Driver 主文件中的 Driver 任务。//Defining package of the class package com.PACKT.chapter1; // Importing java libraries import java.io.*; importorg.apache.hadoop.fs.*; import org.apache.hadoop.io.*; importorg.apache.hadoop.mapred.*; importorg.apache.hadoop.util.*; importorg.apache.hadoop.conf.*; //Defining wordcount class for job configuration // information public class WordCount extends Configured implements Tool{ publicint run(String[] args) throws IOException{ JobConfconf = new JobConf(WordCount.class); conf.setJobName("wordcount"); //For defining the output key format conf.setOutputKeyClass(Text.class); //For defining the output value format conf.setOutputValueClass(IntWritable.class); // For defining the Mapper class implementation conf.setMapperClass(Map.class); // For defining the Reducer class implementation conf.setReducerClass(Reduce.class); // For defining the type of input format conf.setInputFormat(TextInputFormat.class); // For defining the type of output format conf.setOutputFormat(TextOutputFormat.class); // For defining the command line argument sequence for // input dataset path FileInputFormat.setInputPaths(conf, new Path(args[0])); // For defining the command line argument sequence for // output dataset path FileOutputFormat.setOutputPath(conf, new Path(args[1])); // For submitting the configuration object JobClient.runJob(conf); return 0; } // Defining the main() method to start the execution of // the MapReduce program public static void main(String[] args) throws Exception { intexitCode = ToolRunner.run(new WordCount(), args); System.exit(exitCode); } }
-
-
编译 Java 类。
// create a folder for storing the compiled classes hduser@ubuntu:~/Desktop/PacktPub$ mkdir classes // compile the java class files with classpath hduser@ubuntu:~/Desktop/PacktPub$ javac -classpath /usr/local/hadoop/hadoop-core-1.1.0.jar:/usr/local/hadoop/lib/commons-cli-1.2.jar -d classes *.java -
从编译后的类创建一个
.jar文件。hduser@ubuntu:~/Desktop/PacktPub$ cd classes/ // create jar of developed java classes hduser@ubuntu:~/Desktop/PacktPub/classes$ jar -cvf wordcount.jar com -
启动 Hadoop 守护进程。
// Go to Hadoop home Directory hduser@ubuntu:~$ cd $HADOOP_HOME // Start Hadoop Cluster hduser@ubuntu:/usr/local/hadoop$ bin/start-all.sh -
检查所有正在运行的守护进程。
// Ensure all daemons are running properly hduser@ubuntu:/usr/local/hadoop$ jps -
创建 HDFS 目录
/wordcount/input/。// Create Hadoop directory for storing the input dataset hduser@ubuntu:/usr/local/hadoop$ bin/Hadoop fs -mkdir /wordcount/input -
提取用于词频统计示例的输入数据集。由于我们需要有文本文件来供词频统计示例处理,因此我们将通过将 Hadoop 发行版中提供的文本文件(
CHANGES.txt、LICENSE.txt、NOTICE.txt和README.txt)复制到 Hadoop 目录来使用它们。我们也可以在这个 MapReduce 算法中使用来自互联网的其他文本数据集,而不是使用现成的文本文件。我们也可以从互联网上提取数据进行处理,但在这里我们使用的是现成的输入文件。 -
将所有文本文件复制到 HDFS。
// To copying the text files from machine's local // directory in to Hadoop directory hduser@ubuntu:/usr/local/hadoop$ bin/hadoopfs -copyFromLocal $HADOOP_HOME/*.txt /wordcount/input/ -
使用以下命令运行 Hadoop MapReduce 作业:
// Command for running the Hadoop job by specifying jar, main class, input directory and output directory. hduser@ubuntu:/usr/local/hadoop$ bin/hadoop jar wordcount.jar com.PACKT.chapter1.WordCount /wordcount/input/ /wordcount/output/ -
这就是最终输出的样子。
// To read the generated output from HDFS directory hduser@ubuntu:/usr/local/hadoop$ bin/hadoopfs -cat /wordcount/output/part-00000提示
在 MapReduce 阶段,您需要监控作业和节点。使用以下方法在网页浏览器中监控 MapReduce 作业:
-
localhost:50070:NameNode Web 界面(用于 HDFS)
-
localhost:50030:JobTracker Web 界面(用于 MapReduce 层) -
localhost:50060:TaskTracker Web 界面(用于 MapReduce 层)
-
学习如何监控和调试 Hadoop MapReduce 作业
在本节中,我们将学习如何在没有命令的情况下监控和调试 Hadoop MapReduce 作业。
这是使用 Hadoop MapReduce 管理 UI 的最简单方式之一。我们可以通过浏览器访问 http://localhost:50030(JobTracker 守护进程的 web UI)。这将显示 Hadoop MapReduce 作业的日志信息,界面如下所示:

Map/Reduce 管理
在这里,我们可以查看正在运行的作业的信息和状态,作业的 Map 和 Reduce 任务状态,以及过去已完成的作业和失败的作业(包含失败的 Map 和 Reduce 任务)。此外,我们还可以通过点击失败作业中失败的 Map 或 Reduce 任务的超链接来调试 MapReduce 作业。这样会在作业运行时,在标准输出上显示错误信息。
浏览 HDFS 数据
在这一部分中,我们将看到如何在不运行任何 Bash 命令的情况下浏览 HDFS 目录。NameNode 守护进程的 web UI 提供了这样的功能。我们只需要在浏览器中访问 http://localhost:50070 即可。

NameNode 管理
这个 UI 使我们能够获取集群摘要(内存状态)、NameNode 日志以及集群中活跃和死节点的信息。此外,它还允许我们浏览为 Hadoop MapReduce 作业存储输入和输出数据的 Hadoop 目录。
理解几种可能的 MapReduce 定义,以解决商业问题
到目前为止,我们已经了解了什么是 MapReduce 以及如何编写 MapReduce 代码。接下来,我们将查看一些常见的 MapReduce 问题定义,这些问题定义通常用于商业分析。任何了解 MapReduce 和 Hadoop 的读者,都会通过修改用于单词计数的 MapReduce 示例,轻松编写代码并解决这些问题定义。主要的变化将在数据解析和数据操作逻辑上。主要的工作将集中在数据收集、数据清理和数据存储上。
-
服务器 web 日志处理:通过这个 MapReduce 定义,我们可以进行 web 日志分析。web 服务器的日志提供了关于 web 请求的信息,比如请求的页面 URL、日期、时间和协议。从这些信息中,我们可以从 web 服务器日志中识别出我们网站的高峰负载时段,并根据网站的流量调整 web 服务器的配置。因此,识别出夜间没有流量的时间段将帮助我们通过缩减服务器规模来节省费用。此外,还有许多商业案例可以通过这种 web 日志服务器分析来解决。
-
网站分析与网站统计:网站统计能够提供关于访客元数据的更详细信息,例如来源、广告活动、访客类型、访客位置、搜索关键词、请求的页面 URL、浏览器以及在页面上花费的总时间。Google Analytics 是其中一个流行且免费的服务提供商,通过分析所有这些信息,我们可以了解访客在网站上的行为。通过描述性分析,我们可以基于访客对页面的依赖性,识别网站页面或其他网页属性的重要性。对于电子商务网站,我们可以根据访客的访问总数、页面浏览量以及在页面上花费的时间来识别热门产品。此外,还可以在网站数据上实施预测分析,以预测业务趋势。
-
搜索引擎:假设我们有大量的文档,并希望在这些文档中搜索特定的关键词,使用 Hadoop MapReduce 的倒排索引将帮助我们找到关键词,从而为大数据构建一个搜索引擎。
-
股市分析:假设我们收集了长期的股市数据(大数据),现在希望识别其中的模式并预测下一时间段的走势。这需要对所有历史数据集进行训练。然后,我们可以使用多个机器学习库与 Hadoop MapReduce 计算股市在特定时间段内的变化频率。
此外,还有许多可以应用 MapReduce 的场景,帮助降低企业成本。
学习在 R 中编写 Hadoop MapReduce 的不同方法
我们知道,Hadoop 大数据处理与 MapReduce 对于统计学家、网站分析师和产品经理来说非常重要,尤其是对于那些曾经使用 R 工具进行分析的人,因为将分析迁移到 MapReduce 和 Hadoop 上需要额外的编程知识。同时,我们也知道 R 是一个持续增长受欢迎的工具;有许多开发中的包/库可以与 R 集成。因此,要开发一个结合 R 的日志和 Hadoop 的计算能力的 MapReduce 算法或程序,我们需要 R 和 Hadoop 之间的中间件。RHadoop、RHIPE 和 Hadoop streaming 是帮助在 R 中开发和执行 Hadoop MapReduce 的中间件。在最后一部分中,我们将介绍 RHadoop、RHIPE,并介绍 Hadoop streaming,从后面的章节开始,我们将仅使用这些包来开发 MapReduce。
学习 RHadoop
RHadoop 是一个出色的开源软件框架,用于通过 R 函数在 Hadoop 平台上执行数据分析。RHadoop 由Revolution Analytics开发,是基于开源 R 项目进行统计计算的领先商业软件和服务提供商。RHadoop 项目有三个不同的 R 包:rhdfs、rmr和rhbase。所有这些包都在 Cloudera 的 Hadoop 发行版 CDH3、CDH4 和 R 2.15.0 上实现和测试。此外,这些包还与 Revolution Analytics 的 R 版本 4.3、5.0 和 6.0 发行版进行了测试。
这三个不同的 R 包是基于 Hadoop 的两个主要特性 HDFS 和 MapReduce 设计的:
-
rhdfs:这是一个为 R 提供所有 Hadoop HDFS 访问的 R 包。所有分布式文件都可以通过 R 函数进行管理。 -
rmr:这是一个为 R 提供 Hadoop MapReduce 接口的 R 包。借助这个包,Mapper 和 Reducer 可以轻松开发。 -
rhbase:这是一个用于通过 R 处理 HBase 分布式数据库数据的 R 包。
学习 RHIPE
R 和 Hadoop 集成编程环境(RHIPE)是一个自由和开源的项目。RHIPE 广泛用于通过D&R分析执行大数据分析。D&R 分析用于将庞大的数据划分、在分布式网络上并行处理以生成中间输出,最后将所有这些中间输出重新组合成一个集合。RHIPE 旨在通过 R 在 Hadoop 平台上进行复杂大数据的 D&R 分析。RHIPE 由Saptarshi Joy Guha(Mozilla 公司数据分析师)及其团队开发,作为她在普渡大学统计系的博士论文的一部分。
学习 Hadoop streaming
Hadoop streaming 是 Hadoop 发行版中提供的一个工具。该工具允许你使用任何可执行文件或脚本作为 Mapper 和/或 Reducer 创建并运行 MapReduce 作业。它支持 R、Python、Ruby、Bash、Perl 等语言。我们将使用 R 语言和 bash 脚本。
另外,还有一个名为HadoopStreaming的 R 包,它是为在 Hadoop 集群上通过 R 脚本执行数据分析而开发的,这是一个 R 与 Hadoop streaming 的接口。此外,它还允许在没有 Hadoop 的情况下运行 MapReduce 任务。该包由David Rosenberg(SenseNetworks 的首席科学家)开发,他在机器学习和统计建模方面具有专业知识。
总结
在本章中,我们已经了解了 Hadoop MapReduce 是什么,以及如何开发和运行它。在下一章中,我们将学习如何安装 RHIPE 和 RHadoop,并通过示例开发 MapReduce 及其可用的功能库。
第三章. R 与 Hadoop 的集成
从前两章我们获取了关于如何安装 R 与 Hadoop 工具的基本信息。同时,我们也了解了 Hadoop 的关键特性以及为什么它们与 R 集成,用于解决大数据业务问题。因此,借助 R 与 Hadoop 的集成,我们可以将数据分析提升到大数据分析的层面。这两个中间件仍在不断改进,以便彼此兼容使用。
在第二章,编写 Hadoop MapReduce 程序中,我们学习了如何在 Hadoop 中编写 MapReduce 程序。在本章中,我们将学习如何在 R 中开发在 Hadoop 集群上运行的 MapReduce 程序。本章将提供关于 R 和 Hadoop 以及 RHIPE 和 RHadoop 的开发教程。安装 R 和 Hadoop 后,我们将看到如何通过简单步骤将 R 与 Hadoop 进行集成。
在我们开始安装之前,先来看看 R 与 Hadoop 集成在组织中的优势。由于统计学家和数据分析师常常使用 R 工具进行数据探索和数据分析,Hadoop 集成为处理大规模数据提供了极大的便利。同样,使用 Hadoop 工具(如系统)来组织数据仓库的数据工程师,可以通过与 R 工具的集成,执行逻辑分析操作,从而获得可操作的有价值的洞见。
因此,这些基于数据的工具和技术的集成可以构建一个强大且可扩展的系统,具备两者的特性。

将 R 与 Hadoop 连接的三种方式如下:
-
RHIPE
-
RHadoop
-
Hadoop 流式处理
在本章中,我们将学习使用 RHIPE 和 RHadoop 进行集成与分析。Hadoop 流式处理将在第四章,使用 Hadoop 流式处理与 R中讲解。
介绍 RHIPE
RHIPE代表R 和 Hadoop 集成编程环境。正如在www.datadr.org/上所提到的,它在希腊语中意为“瞬间”,是 R 与 Hadoop 的结合体。它最初由Saptarshi Guha为其在普渡大学统计系的博士论文于 2012 年开发。现在由普渡大学统计系团队及其他活跃的 Google 讨论组进行维护。
RHIPE 包使用分割与重组合技术对大数据进行数据分析。在此技术中,数据被划分为子集,针对这些子集执行特定的 R 分析操作,最后将输出结果合并。RHIPE 主要旨在实现以下两个目标:
-
让你能够对大数据和小数据进行深入分析。
-
允许用户使用较低级语言在 R 中执行分析操作。RHIPE 设计有多个函数,可帮助在简单的 R 控制台中执行 Hadoop 分布式文件系统(HDFS)以及 MapReduce 操作。
RHIPE 是与 HDFS 和 MapReduce 操作相比较的较低级接口。使用最新支持的 RHIPE 版本 0.73.1,文件名为 Rhipe_0.73.1-2.tar.gz。
安装 RHIPE
由于 RHIPE 是 R 和 Hadoop 的连接器,我们需要按照以下顺序在我们的机器或集群中安装 Hadoop 和 R:
-
安装 Hadoop。
-
安装 R。
-
安装协议缓冲区。
-
设置环境变量。
-
安装 rJava。
-
安装 RHIPE。
让我们开始安装。
安装 Hadoop
由于我们在这里要将 R 和 Hadoop 与 RHIPE 包库集成,因此需要在我们的机器上安装 Hadoop。这将是一个单节点或多节点安装,具体取决于要分析的数据大小。
由于我们已经学会了如何在 Ubuntu 上安装 Hadoop,我们在此不再重复该过程。如果您尚未安装,请参阅 第一章,准备使用 R 和 Hadoop,以获取指导。
安装 R
如果我们使用多节点 Hadoop 架构,则有多个 TaskTracker 节点用于执行 MapReduce 作业。因此,我们需要在所有这些 TaskTracker 节点上安装 R。这些 TaskTracker 节点将根据键值对的考虑,使用开发的映射和减少逻辑启动数据子集的过程。
安装协议缓冲区
协议缓冲区只需将数据序列化,使其平台无关、中立和健壮(主要用于结构化数据)。Google 使用相同的协议进行数据交换。RHIPE 依赖于协议缓冲区 2.4.1 以进行网络上的数据序列化。
可以使用以下命令安装:
## For downloading the protocol buffer 2.4.1
wget http://protobuf.googlecode.com/files/protobuf-2.4.1.tar.gz
## To extracting the protocol buffer
tar -xzf protobuf-2.4.1.tar.gz
## To get in to the extracted protocol buffer directory
cd protobuf-2.4.1
## For making install the protocol buffer
./configure # --prefix=...
make
make install
环境变量
为了使 RHIPE 能够正确编译和工作,最好确保以下环境变量设置正确:
为了配置 Hadoop 库,我们需要将两个变量 PKG_CONFIG_PATH 和 LD_LIBRARY_PATH 设置到 hduser(Hadoop 用户)的 ~./bashrc 文件中,以便在用户登录系统时自动设置。
这里,PKG_CONFIG_PATH 是一个环境变量,保存了系统中安装库的 pkg-config 脚本路径,而 LD_LIBRARY_PATH 是一个环境变量,保存了本地共享库的路径。
export PKG_CONFIG_PATH = /usr/local/lib
export LD_LIBRARY_PATH = /usr/local/lib
您还可以从 R 控制台设置所有这些变量,如下所示:
Sys.setenv(HADOOP_HOME="/usr/local/hadoop/")
Sys.setenv(HADOOP_BIN="/usr/local/hadoop/bin")
Sys.setenv(HADOOP_CONF_DIR="/usr/local/hadoop/conf")
其中 HADOOP_HOME 用于指定 Hadoop 目录的位置,HADOOP_BIN 用于指定 Hadoop 二进制文件的位置,HADOOP_CONF_DIR 用于指定 Hadoop 配置文件的位置。
设置变量是临时的,并且在特定的 R 会话期间有效。如果我们希望在每次 R 会话初始化时自动初始化这些变量,使其永久有效,我们需要将这些变量设置到 /etc/R/Renviron 文件中,就像在特定用户配置文件的 .bashrc 中设置环境变量一样。
rJava 包安装
由于 RHIPE 是一个 Java 包,它充当 R 和 Hadoop 之间的 Java 桥梁。RHIPE 将输入数据序列化为 Java 类型,这些数据需要在集群上序列化。它需要一个低级的 Java 接口,而这一接口由 rJava 提供。因此,我们将安装 rJava 以启用 RHIPE 的功能。
## For installing the rJava Package will be used for calling java libraries from R.
install.packages("rJava")
安装 RHIPE
现在,是时候从 RHIPE 的软件库安装 RHIPE 包了。
## Downloading RHIPE package from RHIPE repository
Wget http://ml.stat.purdue.edu/rhipebin/Rhipe_0.73.1-2.tar.gz
## Installing the RHIPE package in R via CMD command
R CMD INSTALL Rhipe_0.73.1.tar.gz
现在,我们已准备好一个 RHIPE 系统,可以使用 R 和 Hadoop 执行数据分析。
理解 RHIPE 的架构
让我们理解 RHIPE 库包的工作原理,RHIPE 被开发出来用于将 R 和 Hadoop 集成,以进行高效的大数据分析。

RHIPE 的组件
有许多 Hadoop 组件将用于与 R 和 Hadoop 的数据分析操作。
RHIPE 的组件如下:
-
RClient:RClient 是一个 R 应用程序,它调用 JobTracker 来执行作业,并指示多个 MapReduce 作业资源,如 Mapper、Reducer、输入格式、输出格式、输入文件、输出文件以及其他能处理 MapReduce 作业的参数。
-
JobTracker:JobTracker 是 Hadoop MapReduce 操作的主节点,负责初始化并监控 Hadoop 集群上的 MapReduce 作业。
-
TaskTracker:TaskTracker 是 Hadoop 集群中的一个从节点,负责根据 JobTracker 的指令执行 MapReduce 作业,获取输入数据块,并在其上运行 R 特定的
Mapper和Reducer。最终,输出将被写入 HDFS 目录。 -
HDFS:HDFS 是一个分布式文件系统,部署在 Hadoop 集群上,包含多个数据节点。它为各种数据操作提供数据服务。
理解 RHIPE 示例
在本节中,我们将创建两个 RHIPE MapReduce 示例。这两个示例通过 RHIPE 包中的基本 Hadoop MapReduce 作业功能来定义。
RHIPE 示例程序(仅 Map 阶段)
MapReduce 问题定义:这个 MapReduce 示例程序的目标是通过在 Hadoop 环境中使用 min 和 max 函数对数值数据进行测试,以验证 RHIPE 的安装。由于这是一个示例程序,我们只包含了 Map 阶段,并将其输出存储在 HDFS 目录中。
要开始使用 RHIPE 开发,我们需要通过加载库并调用 rhinit() 方法来初始化 RHIPE 子系统。
## Loading the RHIPE library
library(Rhipe)
## initializing the RHIPE subsystem, which is used for everything. RHIPE will not work if rhinit is not called.
rhinit()
输入:我们插入一个数值,而不是使用文件作为输入。
Map 阶段:该 MapReduce 程序的 Map 阶段将调用 10 次不同的迭代,在每次迭代中,根据迭代次数生成 1 到 10 之间的随机数。之后,将计算这些生成的数值的最大值和最小值。
## Defining the Map phase
Map(function(k,v){
## for generating the random deviates
X runif(v)
## for emitting the key-value pairs with key – k and
## value – min and max of generated random deviates.
rhcollect(k, c(Min=min(x),Max=max(x))
}
输出:最终,Map 阶段的输出将作为此 MapReduce 作业的输出,并将存储到 HDFS 中的/app/hadoop/RHIPE/路径下。
通过 RHIPE 包的rhwatch()方法定义 MapReduce 作业:
## Create and running a MapReduce job by following
job = rhwatch(map=map,input=10,reduce=0,
output="/app/Hadoop/RHIPE/test",jobname='test')
从 HDFS 读取 MapReduce 输出:
## Read the results of job from HDFS
result <- rhread(job)
要以更可读的表格格式显示结果,请使用以下代码:
## Displaying the result
outputdata <- do.call('rbind', lapply(result, "[", 2))
输出:

理解 RHIPE 函数参考
RHIPE 特别设计为提供 Hadoop 的低级接口。因此,拥有 RHIPE 包的 R 用户可以轻松地对存储在 HDFS 上的大数据集执行 Hadoop 数据操作,就像在 R 中调用print()函数一样。
现在我们将看到 RHIPE 库中所有方法的所有可能功能用法。所有这些方法都分为三类:初始化、HDFS 和 MapReduce 操作。
初始化
我们使用以下命令进行初始化:
-
rhinit:用于初始化 Rhipe 子系统。rhinit(TRUE,TRUE)
HDFS
我们使用以下命令进行 HDFS 操作:
-
rhls:用于从 HDFS 检索所有目录。其语法为
rhls(path)rhls("/")输出:
![HDFS]()
-
hdfs.getwd:用于获取当前工作 HDFS 目录。其语法为hdfs.getwd()。 -
hdfs.setwd:用于设置当前工作 HDFS 目录。其语法为hdfs.setwd("/RHIPE") -
rhput:用于将文件从本地目录复制到 HDFS。其语法为rhput(src,dest)和rhput("/usr/local/hadoop/NOTICE.txt","/RHIPE/")。 -
rhcp:用于将文件从一个 HDFS 位置复制到另一个 HDFS 位置。其语法为rhcp('/RHIPE/1/change.txt','/RHIPE/2/change.txt')。 -
rhdel:用于从 HDFS 删除目录/文件。其语法为rhdel("/RHIPE/1")。 -
rhget:用于将 HDFS 文件复制到本地目录。其语法为rhget("/RHIPE/1/part-r-00000", "/usr/local/")。 -
rwrite:用于将 R 数据写入 HDFS。其语法为rhwrite(list(1,2,3),"/tmp/x")。
MapReduce
我们使用以下命令进行 MapReduce 操作:
-
rhwatch:用于准备、提交并监控 MapReduce 作业。# Syntax: rhwatch(map, reduce, combiner, input, output, mapred,partitioner,mapred, jobname) ## to prepare and submit MapReduce job: z=rhwatch(map=map,reduce=0,input=5000,output="/tmp/sort",mapred=mapred,read=FALSE) results <- rhread(z) -
rhex:用于从 Hadoop 集群上执行 MapReduce 作业。## Submit the job rhex(job) -
rhjoin:用于检查 MapReduce 作业是否已完成。其语法为rhjoin(job)。 -
rhkill:用于终止正在运行的 MapReduce 作业。其语法为rhkill(job)。 -
rhoptions:用于获取或设置 RHIPE 配置选项。其语法为rhoptions()。 -
rhstatus:用于获取 RHIPE MapReduce 作业的状态。其语法为rhstatus(job)。rhstatus(job, mon.sec = 5, autokill = TRUE,showErrors = TRUE, verbose = FALSE, handler = NULL)
介绍 RHadoop
RHadoop 是一个包含三个 R 包的集合,用于在 R 环境中提供大数据操作。它由 Revolution Analytics 开发,Revolution Analytics 是基于 R 的商业软件的领先提供商。RHadoop 提供三个主要的 R 包:rhdfs、rmr 和 rhbase。每个包提供不同的 Hadoop 功能。
-
rhdfs是一个 R 接口,提供从 R 控制台访问 HDFS 的功能。由于 Hadoop MapReduce 程序将输出写入 HDFS,因此通过调用rhdfs方法,可以轻松访问它们。R 程序员可以轻松地对分布式数据文件执行读写操作。基本上,rhdfs包通过后台调用 HDFS API 来操作存储在 HDFS 上的数据源。 -
rmr是一个 R 接口,用于在 R 环境内提供 Hadoop MapReduce 功能。因此,R 程序员只需要将应用逻辑分为 map 和 reduce 阶段,并使用rmr方法提交。之后,rmr会调用 Hadoop streaming MapReduce API,输入参数包括输入目录、输出目录、mapper、reducer 等,来在 Hadoop 集群上执行 R MapReduce 作业。 -
rhbase是一个 R 接口,用于通过 Thrift 服务器操作存储在分布式网络上的 Hadoop HBase 数据源。rhbase包设计了多个方法,用于初始化、读写和表操作。
在这里,运行 Hadoop MapReduce 操作并不一定需要安装所有三个 RHadoop 包。如果我们将输入数据源存储在 HBase 数据源中,我们需要安装 rhbase;否则,我们需要 rhdfs 和 rmr 包。由于 Hadoop 主要因其两个主要特性——Hadoop MapReduce 和 HDFS——而广受欢迎,这两个特性将在 R 控制台中通过 RHadoop 的 rhdfs 和 rmr 包得到应用。这些包足以在 R 中运行 Hadoop MapReduce。基本上,rhdfs 提供 HDFS 数据操作,而 rmr 提供 MapReduce 执行操作。
RHadoop 还包括另一个名为 quick check 的包,用于调试由 rmr 包定义的 MapReduce 作业。
在接下来的部分,我们将看到它们的架构关系以及安装步骤。
理解 RHadoop 架构
由于 Hadoop 因 HDFS 和 MapReduce 而非常受欢迎,Revolution Analytics 开发了单独的 R 包,即 rhdfs、rmr 和 rhbase。RHadoop 的架构如以下图所示:

RHadoop 生态系统
安装 RHadoop
本节将介绍三个 RHadoop 包的安装技巧以及它们的前提条件。
-
R 和 Hadoop 安装:由于我们将使用 R 和 Hadoop 集成的环境,因此需要在计算机上安装 Hadoop 和 R。如果尚未安装,请参阅 第一章,准备使用 R 和 Hadoop。如我们所知,如果数据量过大,需要通过增加节点数来扩展集群。基于此,为了在系统上安装 RHadoop,我们需要根据数据的大小安装单节点或多节点 Hadoop。
RHadoop 已经在 Cloudera、Hortonworks 和 MapR 提供的多个 Hadoop 发行版上进行了测试。
-
安装 R 包:我们需要安装多个 R 包,它们帮助 R 与 Hadoop 连接。包的列表如下:
-
rJava
-
RJSONIO
-
itertools
-
digest
-
Rcpp
-
httr
-
functional
-
devtools
-
plyr
-
reshape2
我们可以通过在 R 控制台中执行以下 R 命令来安装它们:
install.packages( c('rJava','RJSONIO', 'itertools', 'digest','Rcpp','httr','functional','devtools', 'plyr','reshape2')) -
-
设置环境变量:我们可以通过 R 控制台使用以下代码来设置环境变量:
## Setting HADOOP_CMD Sys.setenv(HADOOP_CMD="/usr/local/hadoop/bin/hadoop") ## Setting up HADOOP_STREAMING Sys.setenv(HADOOP_STREAMING="/usr/local/hadoop/contrib/streaming/hadoop-streaming-1.0.3.jar")或者,我们也可以通过命令行设置 R 控制台,如下所示:
export HADOOP_CMD=/usr/local/Hadoop export HADOOP_STREAMING=/usr/lib/hadoop-0.20-mapreduce/contrib/streaming/hadoop-streaming-2.0.0-mr1-cdh4.1.1.jar -
安装 RHadoop [
rhdfs,rmr,rhbase]-
从 Revolution Analytics 的 GitHub 仓库下载 RHadoop 软件包:
github.com/RevolutionAnalytics/RHadoop。-
rmr:[rmr-2.2.2.tar.gz] -
rhdfs:[rhdfs-1.6.0.tar.gz] -
rhbase:[rhbase-1.2.0.tar.gz]
-
-
安装软件包。
-
对于 rmr,我们使用:
R CMD INSTALL rmr-2.2.2.tar.gz -
对于
rhdfs,我们使用:R CMD INSTALL rmr-2.2.2.tar.gz -
对于
rhbase,我们使用:R CMD INSTALL rhbase-1.2.0.tar.gz
提示
要安装 rhbase,我们需要在 Hadoop 集群上安装 HBase 和 Zookeeper。
-
-
理解 RHadoop 示例
一旦完成 RHadoop 的安装,我们可以通过运行 RHadoop 示例程序中的rmr2和rhdfs库来测试设置,如下所示:
## loading the libraries
library(rhdfs')
library('rmr2')
## initializing the RHadoop
hdfs.init()
# defining the input data
small.ints = to.dfs(1:10)
## Defining the MapReduce job
mapreduce(
# defining input parameters as small.ints hdfs object, map parameter as function to calculate the min and max for generated random deviates.
input = small.ints,
map = function(k, v)
{
lapply(seq_along(v), function(r){
x <- runif(v[[r]])
keyval(r,c(max(x),min(x)))
})})
运行这些代码行后,按下Ctrl + Enter将执行此 MapReduce 程序。如果成功,最后一行将如下面的截图所示:

那一行字符表示 MapReduce 作业的输出位置。
要读取已执行 MapReduce 作业的结果,复制最后一行提供的输出位置,并将其传递给rhdfs的from.dfs()函数。

其中,前一输出的第一列表示最大值,第二列表示最小值。
单词计数
MapReduce 问题定义:这个 RHadoop MapReduce 程序定义了识别提供的输入文本文件中所有单词频率的任务。
同样,请注意,这是我们在第二章 编写 Hadoop MapReduce 程序中学习的相同 MapReduce 问题。
wordcount = function(input, output = NULL, pattern = " "){
Map 阶段:这个map函数将逐行读取文本文件并按空格拆分。这个 Map 阶段将给所有被映射器捕获的单词分配1作为值。
wc.map = function(., lines) {
keyval(
unlist(
strsplit(
x = lines,
split = pattern)),
1)}
Reduce 阶段:Reduce 阶段将通过对具有相同键的单词进行求和操作来计算所有单词的总频率。
wc.reduce = function(word, counts ) {
keyval(word, sum(counts))}
定义 MapReduce 作业:在定义完单词计数的映射器和归约器之后,我们需要创建driver方法来启动 MapReduce 的执行。
# To execute the defined Mapper and Reducer functions
# by specifying the input, output, map, reduce and input.format as parameters.
# Syntax:
# mapreduce(input, output, input.format, map,reduce,
# combine)
mapreduce(input = input ,
output = output,
input.format = "text",
map = wc.map,
reduce = wc.reduce,
combine = T)}
执行 MapReduce 作业:我们将通过传递输入数据位置作为wordcount函数的参数来执行 RHadoop MapReduce 作业。
wordcount('/RHadoop/1/')
探索wordcount输出:
from.dfs("/tmp/RtmpRMIXzb/file2bda5e10e25f")
理解 RHadoop 函数参考
RHadoop 有三个不同的包,分别用于 HDFS、MapReduce 和 HBase 操作,以便对数据执行操作。
在这里,我们将看到如何使用rmr和rhdfs包中的函数:
hdfs 包
分类函数如下:
-
初始化
-
hdfs.init:用于初始化rhdfs包。其语法为hdfs.init()。 -
hdfs.defaults:用于检索和设置rhdfs的默认值。其语法为hdfs.defaults()。
要检索
hdfs配置的默认值,请参考以下截图:![HDFS 包]()
-
-
文件操作
-
hdfs.put:用于将文件从本地文件系统复制到 HDFS 文件系统。hdfs.put('/usr/local/hadoop/README.txt','/RHadoop/1/') -
hdfs.copy:用于将文件从 HDFS 目录复制到本地文件系统。hdfs.put('/RHadoop/1/','/RHadoop/2/') -
hdfs.move:用于将文件从一个 HDFS 目录移动到另一个 HDFS 目录。hdfs.move('/RHadoop/1/README.txt','/RHadoop/2/') -
hdfs.rename:用于重命名存储在 HDFS 中的文件(从 R 中进行操作)。hdfs.rename('/RHadoop/README.txt','/RHadoop/README1.txt') -
hdfs.delete:用于从 R 中删除 HDFS 文件或目录。hdfs.delete("/RHadoop") -
hdfs.rm:用于从 R 中删除 HDFS 文件或目录。hdfs.rm("/RHadoop") -
hdfs.chmod:用于更改某些文件的权限。hdfs.chmod('/RHadoop', permissions= '777')
-
-
文件读/写:
-
hdfs.file:用于初始化文件,以便进行读/写操作。f = hdfs.file("/RHadoop/2/README.txt","r",buffersize=104857600) -
hdfs.write:用于通过流写入存储在 HDFS 中的文件。f = hdfs.file("/RHadoop/2/README.txt","r",buffersize=104857600) hdfs.write(object,con,hsync=FALSE) -
hdfs.close:用于在文件操作完成后关闭流。它会关闭流并且不允许进一步的文件操作。hdfs.close(f) -
hdfs.read:用于从 HDFS 目录中的二进制文件中读取。这将使用流来反序列化数据。f = hdfs.file("/RHadoop/2/README.txt","r",buffersize=104857600)
m = hdfs.read(f)
c = rawToChar(m)
print(c)
-
-
目录操作:
-
hdfs.dircreate或hdfs.mkdir:这两个函数用于在 HDFS 文件系统上创建目录。hdfs.mkdir("/RHadoop/2/") -
hdfs.rm或hdfs.rmr或hdfs.delete- 用于从 HDFS 删除目录或文件。hdfs.rm("/RHadoop/2/")
-
-
工具:
-
hdfs.ls:用于列出 HDFS 中的目录。Hdfs.ls('/')![The hdfs package]()
-
hdfs.file.info:用于获取存储在 HDFS 中的文件的元信息。hdfs.file.info("/RHadoop")
![The hdfs package]()
-
rmr 包
这些函数的类别如下:
-
对于数据存储和检索:
-
to.dfs:用于从文件系统中写入或写出 R 对象。small.ints = to.dfs(1:10)
-
from.dfs:用于读取以二进制加密格式存储在 HDFS 文件系统中的 R 对象。from.dfs('/tmp/RtmpRMIXzb/file2bda3fa07850')
-
-
对于 MapReduce:
-
mapreduce:用于定义和执行 MapReduce 任务。mapreduce(input, output, map, reduce, combine, input.fromat, output.format, verbose)
-
keyval:用于创建和提取键值对。keyval(key, val)
-
总结
由于 RHadoop 被认为是成熟的,我们将在后续章节中进行数据分析时考虑它。在第五章,《学习 R 和 Hadoop 的数据分析》和第六章,《理解机器学习的大数据分析》中,我们将深入探讨一些大数据分析技术,并看到如何使用 RHadoop 解决现实世界中的问题。到目前为止,我们已经学习了如何使用 RHIPE 和 RHadoop 编写 MapReduce 程序。在下一章中,我们将看到如何使用 Hadoop 流式工具和 Hadoop 流式 R 包编写 Hadoop MapReduce 程序。
第四章. 使用 Hadoop Streaming 与 R
在上一章中,我们学习了如何借助 RHIPE 和 RHadoop 将 R 与 Hadoop 进行集成,并且通过示例进行演示。在本章中,我们将讨论以下主题:
-
理解 Hadoop Streaming 的基础
-
理解如何使用 R 运行 Hadoop Streaming
-
探索 HadoopStreaming R 包
理解 Hadoop Streaming 的基础
Hadoop Streaming 是一个 Hadoop 工具,用于通过可执行脚本(如 Mapper 和 Reducer)运行 Hadoop MapReduce 作业。这类似于 Linux 中的管道操作。通过这种方式,文本输入文件会被打印到流中(stdin),该流作为输入提供给 Mapper,Mapper 的输出(stdout)则作为输入提供给 Reducer;最终,Reducer 将输出写入 HDFS 目录。
Hadoop Streaming 工具的主要优势在于它允许 Java 以及非 Java 编写的 MapReduce 作业在 Hadoop 集群上执行。此外,它还负责处理正在运行的 MapReduce 作业的进度。Hadoop Streaming 支持 Perl、Python、PHP、R 和 C++编程语言。若要运行用其他编程语言编写的应用程序,开发人员只需将应用程序逻辑转换为 Mapper 和 Reducer 部分,并且指定键值输出元素。我们在第二章,编写 Hadoop MapReduce 程序中已经了解到,要创建 Hadoop MapReduce 作业,我们需要 Mapper、Reducer 和 Driver 作为三个主要组件。在这里,当我们用 R 和 Hadoop 实现 MapReduce 时,创建用于运行 MapReduce 作业的驱动程序文件是可选的。
本章的编写目的是为了将 R 与 Hadoop 进行集成。因此,我们将展示 R 与 Hadoop Streaming 的示例。现在,我们将看到如何使用 Hadoop Streaming 与 R 脚本(包括 Mapper 和 Reducer)一起使用。从下图中,我们可以识别出 Hadoop Streaming MapReduce 作业的各个组成部分。

Hadoop Streaming 组件
假设我们已经将 Mapper 和 Reducer 实现为code_mapper.R和code_reducer.R。我们将看到如何在 R 和 Hadoop 的集成环境中运行它们。这可以通过带有各种通用和 Streaming 选项的 Hadoop Streaming 命令来运行。
让我们来看一下 Hadoop Streaming 命令的格式:
bin/hadoop command [generic Options] [streaming Options]
下图展示了 Hadoop Streaming 的执行示例,这是一个带有多个 Streaming 选项的 MapReduce 作业。

Hadoop Streaming 命令选项
在上面的图片中,有大约六个独特的重要组件是执行整个 Hadoop Streaming MapReduce 作业所必需的。它们都属于 Streaming 选项,除了 jar。
以下是前面 Hadoop Streaming 命令的逐行描述:
-
Line 1: 此选项用于指定 Hadoop jar 文件(为 Hadoop jar 设置类路径)。
-
Line 2: 此选项用于指定 HDFS 的输入目录。
-
Line 3: 此选项用于指定 HDFS 的输出目录。
-
Line 4: 此选项用于将文件提供给本地机器。
-
Line 5: 此选项用于定义可用的 R 文件作为 Mapper。
-
Line 6: 此选项用于将文件提供给本地机器。
-
Line 7: 此选项用于定义可用的 R 文件作为 Reducer。
上述命令中的六个主要 Hadoop 流式组件列出了并解释如下:
-
jar: 此选项用于运行带有编码类的 jar 文件,这些类设计用于提供 Java 流功能,以及其他编程的 Mapper 和 Reducer。它被称为 Hadoop 流式 jar。
-
input****: 此选项用于指定输入数据集的位置(存储在 HDFS 上),并传递给 Hadoop 流式 MapReduce 作业。
-
output: 此选项用于指定 HDFS 输出目录(MapReduce 作业的输出将写入该目录),并传递给 Hadoop 流式 MapReduce 作业。
-
file: 此选项用于将 MapReduce 资源(如 Mapper、Reducer 和 Combiner)复制到计算机节点(Tasktrackers),以使其本地化。
-
mapper: 此选项用于标识可执行的
Mapper文件。 -
reducer: 此选项用于标识可执行的
Reducer文件。
还有其他 Hadoop 流式命令选项,但它们是可选的。让我们来看看它们:
-
inputformat: 用于通过指定 Java 类名称来定义输入数据格式。默认情况下,它是TextInputFormat。 -
outputformat: 用于通过指定 Java 类名称来定义输出数据格式。默认情况下,它是TextOutputFormat。 -
partitioner: 用于包括编写的类或文件,以实现将 Mapper 阶段的输出按(键,值)对进行分区。 -
combiner: 用于包括编写的类或文件,用于通过聚合键的值来减少 Mapper 输出的值。另外,我们也可以使用默认的 combiner,它会在将 Mapper 的输出提供给 Reducer 之前,简单地合并所有键属性的值。 -
cmdenv: 此选项用于将环境变量传递给流式命令。例如,可以传递R_LIBS = /your /path /to /R /libraries。 -
inputreader: 可用此选项替代inputformat类来指定记录读取器类。 -
verbose: 用于详细显示输出。 -
numReduceTasks: 此选项用于指定 Reducer 的数量。 -
mapdebug: 当 Mapper 任务失败时,用于调试Mapper文件的脚本。 -
reducedebug: 当 Reducer 任务失败时,用于调试Reducer文件的脚本。
现在,是时候来看一些 Hadoop 流式 MapReduce 作业的通用选项了。
-
conf: 用于指定应用程序配置文件。-conf configuration_file -
D:用于定义特定 MapReduce 或 HDFS 属性的值。例如: -
-D property = value 或指定临时 HDFS 目录。-D dfs.temp.dir=/app/tmp/Hadoop/或指定零 Reducer 的总数:
-D mapred.reduce.tasks=0注意
-D选项仅在工具实现时有效。 -
fs:用于定义 Hadoop NameNode。-fs localhost:port -
jt:用于定义 Hadoop JobTracker。-jt localhost:port -
files:用于指定来自 HDFS 的大型或多个文本文件。-files hdfs://host:port/directory/txtfile.txt -
libjars:用于指定要包含在类路径中的多个 jar 文件。-libjars /opt/ current/lib/a.jar, /opt/ current/lib/b.jar -
archives:用于指定在本地机器上解压的 jar 文件。-archives hdfs://host:fs_port/user/testfile.jar
理解如何使用 R 运行 Hadoop 流式处理
现在,我们了解了 Hadoop 流式处理是什么以及如何使用 Hadoop 通用选项和流式选项调用它。接下来,了解如何开发和运行 R 脚本。为此,我们可以考虑一个比简单的词频统计程序更好的示例。
MapReduce 操作的四个不同阶段如下所述:
-
理解 MapReduce 应用程序
-
理解如何编写 MapReduce 应用程序
-
理解如何运行 MapReduce 应用程序
-
理解如何探索 MapReduce 应用程序的输出
理解 MapReduce 应用程序
问题定义:该问题是根据地理位置对页面访问进行分段。在这个问题中,我们将考虑网站www.gtuadmissionhelpline.com/,该网站旨在为希望进入古吉拉特科技大学的学生提供指导。该网站包含多个领域的学院信息,如工程(大专、学位和硕士)、医学、酒店管理、建筑、药学、MBA 和 MCA。通过这个 MapReduce 应用程序,我们将识别访客在地理位置上的兴趣领域。
例如,来自瓦尔萨德市的大多数在线访客更常访问 MBA 院校的页面。基于此,我们可以识别瓦尔萨德学生的心态;他们对进入 MBA 领域有着浓厚的兴趣。因此,通过这个网站流量数据集,我们可以识别按城市划分的兴趣水平。现在,如果瓦尔萨德没有 MBA 院校,对他们来说将是一个大问题。他们将需要搬到其他城市,这可能会增加他们的教育成本。
通过使用这种数据,古吉拉特科技大学可以为来自不同城市的学生生成有价值的洞察。
输入数据集来源:要执行此类分析,我们需要获取该网站的 Web 流量数据。Google Analytics 是一个流行的免费服务,用于跟踪在线访客的元数据。Google Analytics 按各种维度和指标存储 Web 流量数据。我们需要设计一个特定的查询,从 Google Analytics 中提取数据集。
输入数据集:提取的 Google Analytics 数据集包含以下四个数据列:
-
date:这是访问日期,格式为 YYYY/MM/DD。 -
country:这是访问者所在的国家。 -
city:这是访问者所在的城市。 -
pagePath:这是网站页面的 URL。
输入数据集的头部如下:
$ head -5 gadata_mr.csv
20120301,India,Ahmedabad,/
20120302,India,Ahmedabad,/gtuadmissionhelpline-team
20120302,India,Mumbai,/
20120302,India,Mumbai,/merit-calculator
20120303,India,Chennai,/
预期的输出格式如下图所示:

以下是一个示例输出:

理解如何编写 MapReduce 应用程序
在这一部分中,我们将学习 MapReduce 应用程序的以下两个单元:
-
Mapper 代码
-
Reducer 代码
让我们从 Mapper 代码开始。
Mapper 代码:这个名为 ga-mapper.R 的 R 脚本将处理 MapReduce 作业的 Map 阶段。
Mapper 的工作是处理每一行,提取一对(键,值)并将其传递给 Reducer 以进行分组/聚合。在这个示例中,每一行是输入到 Mapper 的数据,输出为 City:PagePath。City 是键,PagePath 是值。现在 Reducer 可以获取给定城市的所有页面路径,因此可以轻松地进行分组。
# To identify the type of the script, here it is RScript
#! /usr/bin/env Rscript
# To disable the warning massages to be printed
options(warn=-1)
# To initiating the connection to standard input
input <- file("stdin", "r")
Each line has these four fields (date, country, city, and pagePath) in the same order. We split the line by a comma. The result is a vector which has the date, country, city, and pathPath in the indexes 1,2,3, and 4 respectively.
我们分别提取城市和页面路径的第三个和第四个元素。然后,它们将作为键值对写入流并传递给 Reducer 以进一步处理。
# Running while loop until all the lines are read
while(length(currentLine <- readLines(input, n=1, warn=FALSE)) > 0) {
# Splitting the line into vectors by "," separator
fields <- unlist(strsplit(currentLine, ","))
# Capturing the city and pagePath from fields
city <- as.character(fields[3])
pagepath <- as.character(fields[4])
# Printing both to the standard output
print(paste(city, pagepath,sep="\t"),stdout())
}
# Closing the connection to that input stream
close(input)
一旦 Mapper 阶段的输出作为(键,值)对可用,Reducers 将从 stdout 读取按行输出,并将其转换为最终的聚合键值对。
让我们看看 Mapper 输出格式是什么样的,以及 Reducer 输入数据格式是怎样的。
Reducer 代码:这个名为 ga_reducer.R 的 R 脚本将处理 MapReduce 作业的 Reducer 部分。
如我们所讨论的,Mapper 的输出将作为 Reducer 的输入。Reducer 会读取这些城市和页面路径对,并将所有值与其相应的键元素进行合并。
# To identify the type of the script, here it is RScript
#! /usr/bin/env Rscript
# Defining the variables with their initial values
city.key <- NA
page.value <- 0.0
# To initiating the connection to standard input
input <- file("stdin", open="r")
# Running while loop until all the lines are read
while (length(currentLine <- readLines(input, n=1)) > 0) {
# Splitting the Mapper output line into vectors by
# tab("\t") separator
fields <- strsplit(currentLine, "\t")
# capturing key and value form the fields
# collecting the first data element from line which is city
key <- fields[[1]][1]
# collecting the pagepath value from line
value <- as.character(fields[[1]][2])
Mapper 输出以两个主要字段写入,使用 \t 作为分隔符,并按行输出数据;因此,我们通过使用 \t 分割数据,以便从流输入中捕获两个主要属性(键和值)。
收集键和值后,Reducer 会将其与之前捕获的值进行比较。如果之前没有设置,则进行设置;否则,使用 R 中的 combine 函数将其与之前的字符值结合,最后将其打印到 HDFS 输出位置。
# setting up key and values
# if block will check whether key attribute is
# initialized or not. If not initialized then it will be # assigned from collected key attribute with value from # mapper output. This is designed to run at initial time.
if (is.na(city.key)) {
city.key <- key
page.value <- value
}
else {
# Once key attributes are set, then will match with the previous key attribute value. If both of them matched then they will combined in to one.
if (city.key == key) {
page.value <- c(page.value, value)
}
else {
# if key attributes are set already but attribute value # is other than previous one then it will emit the store #p agepath values along with associated key attribute value of city,
page.value <- unique(page.value)
# printing key and value to standard output
print(list(city.key, page.value),stdout())
city.key <- key
page.value <- value
}
}
}
print(list(city.key, page.value), stdout())
# closing the connection
close(input)
理解如何运行 MapReduce 应用程序
在使用 R 语言开发 Mapper 和 Reducer 脚本后,是时候在 Hadoop 环境中运行它们了。在执行这个脚本之前,建议先在简单的管道操作上测试它们,使用样本数据集进行验证。
$ cat gadata_sample.csv | ga_mapper.R |sort | ga_reducer.R
前面的命令将在本地计算机上运行开发的 Mapper 和 Reducer 脚本。但它将类似于 Hadoop 流式作业的运行方式。我们需要测试这个命令,以便发现可能在运行时出现的问题,或者识别编程或逻辑错误。
现在,我们已经测试并准备好使用 Hadoop 流式命令运行 Mapper 和 Reducer。这个 Hadoop 流式操作可以通过调用通用的 jar 命令并附带流式命令选项来执行,就像我们在本章的 理解 Hadoop 流式处理的基础知识 部分中学到的那样。我们可以通过以下方式执行 Hadoop 流式作业:
-
从命令提示符
-
R 或 RStudio 控制台
执行命令与通用命令选项和流式命令选项在两种方式下是相同的。
从命令提示符执行 Hadoop 流式作业
正如我们在 理解 Hadoop 流式处理的基础知识 部分中学到的,使用 R 开发的 Hadoop 流式 MapReduce 作业的执行可以使用以下命令:
$ bin/hadoop jar {HADOOP_HOME}/contrib/streaming/hadoop-streaming-1.0.3.jar
-input /ga/gadaat_mr.csv
-output /ga/output1
-file /usr/local/hadoop/ga/ga_mapper.R
-mapper ga_mapper.R
-file /usr/local/hadoop/ga/ga_ reducer.R
-reducer ga_reducer.R
从 R 或 RStudio 控制台执行 Hadoop 流式作业
作为 R 用户,从 R 控制台运行 Hadoop 流式作业会更合适。这可以通过 system 命令完成:
system(paste("bin/hadoop jar”, “{HADOOP_HOME}/contrib/streaming/hadoop-streaming-1.0.3.jar",
"-input /ga/gadata_mr.csv",
"-output /ga/output2",
"-file /usr/local/hadoop/ga/ga_mapper.R",
"-mapper ga_mapper.R",
"-file /usr/local/hadoop/ga/ga_reducer.R",
"-reducer ga_reducer.R"))
这个前面的命令与您已在命令提示符中使用的命令相似,用于执行带有通用选项和流式选项的 Hadoop 流式作业。
理解如何探索 MapReduce 应用的输出
执行成功后,就该探索输出,以检查生成的输出是否重要。输出将与两个目录 _logs 和 _SUCCESS 一起生成。_logs 用于跟踪所有操作和错误;_SUCCESS 仅在 MapReduce 作业成功完成时生成。
再次,可以通过以下两种方式触发命令:
-
从命令提示符
-
从 R 控制台
从命令提示符查看输出
要列出输出目录中生成的文件,将调用以下命令:
$ bin/hadoop dfs -cat /ga/output/part-* > temp.txt
$ head -n 40 temp.txt
用于检查输出的快照如下:

从 R 或 RStudio 控制台查看输出
相同的命令可以在 R(与 RStudio)控制台中通过 system 方法使用。
dir <- system("bin/hadoop dfs -ls /ga/output",intern=TRUE)
out <- system("bin/hadoop dfs -cat /ga/output2/part-00000",intern=TRUE)
前面函数的截图如下:

理解 Hadoop MapReduce 脚本中使用的基本 R 函数
现在,我们将查看一些在 Hadoop Mapper 和 Reducer 中用于数据处理的基本实用函数:
-
file:此函数用于创建文件连接以进行读写操作。它还用于从stdin或stdout读写。此函数将在 Mapper 和 Reducer 阶段的初始化时使用。Con <- file("stdin", "r") -
write:此函数用于将数据写入文件或标准输入。它将在 Mapper 中设置好键值对后使用。write(paste(city,pagepath,sep="\t"),stdout()) -
print:此函数用于将数据写入文件或标准输入。它将在 Mapper 中准备好键值对后使用。print(paste(city,pagepath,sep="\t"),stdout()) -
close:此函数可用于在读取或写入操作完成后关闭与文件的连接。它可以在所有处理完成时与 Mapper 和 Reducer 一起使用,位于关闭(conn)端。 -
stdin:这是对应输入的标准连接。stdin()函数是一个文本模式连接,返回连接对象。此函数将在 Mapper 和 Reducer 中使用。conn <- file("stdin", open="r") -
stdout:这是对应输出的标准连接。stdout()函数是一个文本模式连接,也会返回对象。此函数将在 Mapper 和 Reducer 中使用。print(list(city.key, page.value),stdout()) ## where city.key is key and page.value is value of that key -
sink:sink将 R 输出发送到连接。如果是文件或流连接,输出将返回到文件或流。这将在 Mapper 和 Reducer 中用于跟踪所有功能输出以及错误。sink("log.txt") k <- 1:5 for(i in 1:k){ print(paste("value of k",k)) }sink() unlink("log.txt")
监控 Hadoop MapReduce 作业
Reducer 阶段的一个小语法错误会导致 MapReduce 作业失败。在 Hadoop MapReduce 作业失败后,我们可以通过 Hadoop MapReduce 管理页面跟踪问题,在该页面上可以获取关于正在运行的作业以及已完成作业的信息。
如果作业失败,我们可以看到已完成/失败的 Map 和 Reduce 作业的总数。点击失败的作业将提供导致这些特定 Mappers 或 Reducers 失败的原因。
同时,我们可以通过 JobTracker 控制台查看正在运行的 MapReduce 作业的实时进度,如下图所示:

监控 Hadoop MapReduce 作业
通过命令,我们可以通过指定其输出目录来检查特定 MapReduce 作业的历史,使用以下命令:
$ bin/hadoop job –history /output/location
以下命令将打印 MapReduce 作业的详细信息、失败的作业以及被终止作业的原因。
$ bin/hadoop job -history all /output/location
上述命令将打印每个任务的成功任务和任务尝试的详细信息。
探索 HadoopStreaming R 包
HadoopStreaming 是一个由 David S. Rosenberg 开发的 R 包。我们可以说这是一个简单的 MapReduce 脚本框架。它还可以在没有 Hadoop 的情况下以流式方式操作数据。我们可以将这个 R 包看作是 Hadoop MapReduce 的启动器。对于任何无法回忆起 Hadoop 流式命令的分析师或开发者,这个包将有助于快速运行 Hadoop MapReduce 作业。
该包的三个主要功能如下:
-
分块数据读取:该包允许分块数据读取和写入 Hadoop 流式处理。此功能将解决内存问题。
-
支持多种数据格式:该软件包允许以三种不同的数据格式读取和写入数据。
-
针对 Hadoop 流式命令的强大工具:该软件包还允许用户为 Hadoop 流式命令指定命令行参数。
本软件包主要设计了三个功能,以高效读取数据:
-
hsTableReader -
hsKeyValReader -
hsLineReader
现在,让我们理解这些功能及其用例。之后,我们将通过单词计数的 MapReduce 作业来理解这些功能。
理解hsTableReader函数
hsTableReader函数设计用于读取表格格式的数据。该函数假设已经与文件建立了输入连接,因此它将检索整行数据。它假设所有具有相同键的行都连续存储在输入文件中。
由于 Hadoop 流式作业保证在提供给 Reducer 之前,Mapper 的输出行会被排序,因此在 Hadoop 流式 MapReduce 作业中不需要使用sort函数。当我们不在 Hadoop 上运行时,必须在Mapper函数执行后显式调用sort函数。
定义hsTableReader函数:
hsTableReader(file="", cols='character',
chunkSize=-1, FUN=print,
ignoreKey=TRUE, singleKey=TRUE, skip=0,
sep='\t', keyCol='key',
FUN=NULL, ,carryMemLimit=512e6,
carryMaxRows=Inf,
stringsAsFactors=FALSE)
上述代码中的术语如下:
-
file:这是一个连接对象、流或字符串。 -
chunkSize:指示函数每次读取的最大行数。-1表示一次读取所有行。 -
cols:表示作为“what”参数扫描的列名列表。 -
skip:用于跳过前 n 行数据。 -
FUN:此函数将使用用户输入的数据。 -
carryMemLimit:指示单个键值的最大内存限制。 -
carryMaxRows:指示要考虑或读取的最大行数。 -
stringsAsFactors:定义是否将字符串转换为因子(TRUE或FALSE)。
例如,文件中的数据:
# Loading libraries
Library("HadoopStreaming")
# Input data String with collection of key and values
str <- " key1\t1.91\nkey1\t2.1\nkey1\t20.2\nkey1\t3.2\nkey2\t1.2\nkey2\t10\nkey3\t2.5\nkey3\t2.1\nkey4\t1.2\n"cat(str)
上述代码的输出如下图所示:

hsTableReader读取的数据如下:
# A list of column names, as'what' arg to scan
cols = list(key='',val=0)
# To make a text connection
con <- textConnection(str, open = "r")
# To read the data with chunksize 3
hsTableReader(con,cols,chunkSize=3,FUN=print,ignoreKey=TRUE)
上述代码的输出如下图所示:

理解hsKeyValReader函数
hsKeyValReader函数设计用于读取以键值对格式存储的数据。该函数还使用chunkSize定义一次读取的行数,每行由键字符串和值字符串组成。
hsKeyValReader(file = "", chunkSize = -1, skip = 0, sep = "\t",FUN = function(k, v) cat(paste(k, v))
该函数的术语与hsTablereader()类似。
示例:
# Function for reading chunkwise dataset
printkeyval <- function(k,v) {cat('A chunk:\n')cat(paste(k,v,sep=': '),sep='\n')}
str <- "key1\tval1\nkey2\tval2\nkey3\tval3\n"
con <- textConnection(str, open = "r")
hsKeyValReader(con, chunkSize=1, FUN=printFn)
上述代码的输出如下图所示:

理解hsLineReader函数
hsLineReader 函数设计用于将整行读取为字符串,而不执行数据解析操作。它反复从文件中读取 chunkSize 行数据,并将这些字符串的字符向量传递给 FUN。
hsLineReader(file = "", chunkSize = 3, skip = 0, FUN = function(x) cat(x, sep = "\n"))
该函数的术语与 hsTablereader() 相似。
示例:
str <- " This is HadoopStreaming!!\n here are,\n examples for chunk dataset!!\n in R\n ?"
# For defining the string as data source
con <- textConnection(str, open = "r")
# read from the con object
hsLineReader(con,chunkSize=2,FUN=print)
上述代码的输出如下图所示:

你可以在cran.r-project.org/web/packages/HadoopStreaming/HadoopStreaming.pdf上获取关于这些方法以及其他现有方法的更多信息。
现在,我们将使用 Hadoop MapReduce 程序实现上述数据读取方法,并在 Hadoop 上运行。在某些情况下,键值对或数据行不会被加载到机器内存中,因此逐块读取数据比改进机器配置更为合适。
问题定义:
Hadoop 词频统计:由于我们已经知道什么是词频统计应用,我们将使用上述方法来实现词频统计的概念。这个 R 脚本已从 HadoopStreaming R 包中复制,这个包可以和 HadoopStreaming R 库一起作为示例代码下载。
输入数据集:该数据集取自俄罗斯作家 列夫·托尔斯泰 的小说 安娜·卡列尼娜 第一章。
R 脚本:本节包含了 Mapper、Reducer 及其他配置参数的代码。
文件:hsWordCnt.R
## Loading the library
library(HadoopStreaming)
## Additional command line arguments for this script (rest are default in hsCmdLineArgs)
spec = c('printDone','D',0,"logical","A flag to write DONE at the end.",FALSE)
opts = hsCmdLineArgs(spec, openConnections=T)
if (!opts$set) {
quit(status=0)
}
# Defining the Mapper columns names
mapperOutCols = c('word','cnt')
# Defining the Reducer columns names
reducerOutCols = c('word','cnt')
# printing the column header for Mapper output
if (opts$mapcols) {
cat( paste(mapperOutCols,collapse=opts$outsep),'\n', file=opts$outcon )
}
# Printing the column header for Reducer output
if (opts$reducecols) {
cat( paste(reducerOutCols,collapse=opts$outsep),'\n', file=opts$outcon )
}
## For running the Mapper
if (opts$mapper) {
mapper <- function(d) {
words <- strsplit(paste(d,collapse=' '),'[[:punct:][:space:]]+')[[1]] # split on punctuation and spaces
words <- words[!(words=='')] # get rid of empty words caused by whitespace at beginning of lines
df = data.frame(word=words)
df[,'cnt']=1
# For writing the output in the form of key-value table format
hsWriteTable(df[,mapperOutCols],file=opts$outcon,sep=opts$outsep)
}
## For chunk wise reading the Mapper output, to be feeded to Reducer hsLineReader(opts$incon,chunkSize=opts$chunksize,FUN=mapper)
## For running the Reducer
} else if (opts$reducer) {
reducer <- function(d) {
cat(d[1,'word'],sum(d$cnt),'\n',sep=opts$outsep)
}
cols=list(word='',cnt=0) # define the column names and types (''-->string 0-->numeric)
hsTableReader(opts$incon,cols,chunkSize=opts$chunksize,skip=opts$skip,sep=opts$insep,keyCol='word',singleKey=T, ignoreKey= F, FUN=reducer)
if (opts$printDone) {
cat("DONE\n");
}
}
# For closing the connection corresponding to input
if (!is.na(opts$infile)) {
close(opts$incon)
}
# For closing the connection corresponding to input
if (!is.na(opts$outfile)) {
close(opts$outcon)
}
运行 Hadoop 流式作业
由于这是一个 Hadoop 流式作业,它将像之前执行的 Hadoop 流式作业一样运行。对于这个例子,我们将使用一个 shell 脚本来执行 runHadoop.sh 文件以运行 Hadoop 流式作业。
设置系统环境变量:
#! /usr/bin/env bash
HADOOP="$HADOOP_HOME/bin/hadoop" # Hadoop command
HADOOPSTREAMING="$HADOOP jar
$HADOOP_HOME/contrib/streaming/hadoop-streaming-1.0.3.jar" # change version number as appropriate
RLIBPATH=/usr/local/lib/R/site-library # can specify additional R Library paths here
设置 MapReduce 作业参数:
INPUTFILE="anna.txt"
HFSINPUTDIR="/HadoopStreaming"
OUTDIR="/HadoopStreamingRpkg_output"
RFILE=" home/hduser/Desktop/HadoopStreaming/inst/wordCntDemo/ hsWordCnt.R"
#LOCALOUT="/home/hduser/Desktop/HadoopStreaming/inst/wordCntDemo/annaWordCnts.out"
# Put the file into the Hadoop file system
#$HADOOP fs -put $INPUTFILE $HFSINPUTDIR
删除现有输出目录:
# Remove the directory if already exists (otherwise, won't run)
#$HADOOP fs -rmr $OUTDIR
设计具有通用选项和流式选项的 Hadoop MapReduce 命令:
MAPARGS="--mapper"
REDARGS="--reducer"
JOBARGS="-cmdenv R_LIBS=$RLIBPATH" # numReduceTasks 0
# echo $HADOOPSTREAMING -cmdenv R_LIBS=$RLIBPATH -input $HFSINPUTDIR/$INPUTFILE -output $OUTDIR -mapper "$RFILE $MAPARGS" -reducer "$RFILE $REDARGS" -file $RFILE
$HADOOPSTREAMING $JOBARGS -input $HFSINPUTDIR/$INPUTFILE -output $OUTDIR -mapper "$RFILE $MAPARGS" -reducer "$RFILE $REDARGS" -file $RFILE
从 HDFS 提取输出到本地目录:
# Extract output
./$RFILE --reducecols > $LOCALOUT
$HADOOP fs -cat $OUTDIR/part* >> $LOCALOUT
执行 Hadoop 流式作业
我们现在可以通过执行命令 runHadoop.sh 来执行 Hadoop 流式作业。为了执行此操作,我们需要设置用户权限。
sudo chmod +x runHadoop.sh
通过以下命令执行:
./runHadoop.sh
最后,它将执行整个 Hadoop 流式作业,然后将输出复制到本地目录。
总结
我们已经学习了大部分将 R 与 Hadoop 集成以执行数据操作的方法。在下一章中,我们将学习如何利用 R 和 Hadoop 解决现实世界的数据分析问题。
第五章 使用 R 和 Hadoop 学习数据分析
在前面的章节中,我们学习了 R 和 Hadoop 的安装、配置和集成。
在本章中,我们将学习如何在集成的 R 和 Hadoop 环境中执行数据分析操作。由于本章旨在介绍数据分析,我们将通过一个有效的数据分析周期来理解这一过程。
在本章中,我们将学习:
-
理解数据分析项目生命周期
-
理解数据分析问题
理解数据分析项目生命周期
在处理数据分析项目时,有一些固定任务需要遵循,以便获得预期的结果。因此,我们将构建一个数据分析项目周期,这将是一组标准的数据驱动流程,旨在有效地将数据转化为洞察力。项目生命周期中定义的数据分析流程应按顺序执行,以便有效地使用输入数据集实现目标。这个数据分析过程可能包括识别数据分析问题、设计和收集数据集、数据分析和数据可视化。
数据分析项目生命周期的各个阶段见下图:

让我们从这些阶段的角度来看一下如何进行数据分析。
确定问题
今天,商业分析趋势通过对 Web 数据集执行数据分析来推动业务增长。由于他们的数据量逐渐增加,他们的分析应用需要具备可扩展性,以便从数据集中提取洞察。
借助 Web 分析,我们可以解决商业分析问题。假设我们有一个大型电子商务网站,我们希望了解如何增加业务量。我们可以通过按受欢迎程度将网站的重要页面分为高、中、低类别,来识别这些重要页面。根据这些流行页面的类型、流量来源和内容,我们将能够制定出通过提高网站流量和改进内容来改善业务的路线图。
设计数据需求
为了对特定问题进行数据分析,需要来自相关领域的数据集。根据领域和问题规格,可以决定数据源,并根据问题定义,定义这些数据集的数据属性。
例如,如果我们要进行社交媒体分析(问题规格),我们可以使用 Facebook 或 Twitter 作为数据源。为了识别用户特征,我们需要用户档案信息、点赞和帖子作为数据属性。
数据预处理
在数据分析中,我们并不总是使用相同的数据源、数据属性、数据工具和算法,因为它们并不总是以相同的格式使用数据。这导致需要进行数据操作,例如数据清洗、数据聚合、数据增强、数据排序和数据格式化,以便将数据提供为所有数据工具和算法所支持的格式,这些工具和算法将用于数据分析。
简而言之,预处理用于执行数据操作,将数据转换为固定的数据格式,然后将数据提供给算法或工具。数据分析过程将以该格式化数据作为输入开始。
在大数据情况下,数据集需要格式化并上传到Hadoop 分布式文件系统(HDFS),并由 Hadoop 集群中的各种节点使用映射器和减少器进一步处理。
对数据进行分析
数据在满足数据分析算法所需格式后,将进行数据分析操作。数据分析操作旨在通过数据挖掘概念从数据中发现有意义的信息,以便做出更好的商业决策。这些操作可能会使用描述性分析或预测性分析来进行商业智能。
数据分析可以通过各种机器学习和自定义算法概念进行,例如回归、分类、聚类和基于模型的推荐。对于大数据,相同的算法可以转换为 MapReduce 算法,在 Hadoop 集群上运行,通过将它们的数据分析逻辑转化为 MapReduce 任务,这些任务将运行在 Hadoop 集群上。这些模型需要通过机器学习概念的各个评估阶段进一步评估和改进。改进或优化后的算法可以提供更好的洞察。
数据可视化
数据可视化用于展示数据分析的输出。可视化是一种交互式的方式来展示数据洞察。可以使用各种数据可视化软件以及 R 包来完成这项工作。R 有多种用于数据集可视化的包。如下所示:
-
ggplot2:这是Dr. Hadley Wickham(had.co.nz/)提出的图形语法的实现。欲了解更多信息,请参阅cran.r-project.org/web/packages/ggplot2/。 -
rCharts:这是一个 R 包,用于通过Markus Gesmann和Diego de Castillo提供的熟悉的网格式绘图界面,创建、定制并发布交互式 JavaScript 可视化。欲了解更多信息,请参阅ramnathv.github.io/rCharts/。
以下是使用 R 进行可视化的一些流行示例:
-
面板比例的图形(
ggplot):下图展示了男性和女性在不同指标下的对比,具体包括教育、收入、预期寿命和识字率,使用ggplot:![数据可视化]()
-
仪表板图表:这是一种
rCharts类型。使用它,我们可以使用 R 构建交互式动画仪表板。![数据可视化]()
理解数据分析问题
在这一部分,我们包含了三个实际的数据分析问题,涉及使用 R 和 Hadoop 技术的各个阶段的基于数据的活动。这些数据分析问题的定义旨在帮助读者理解如何利用 R 的函数、包以及 Hadoop 的计算能力进行大数据分析。
数据分析问题的定义如下:
-
探索网页分类
-
计算股市变化频率
-
预测推土机蓝色书籍的销售价格(案例研究)
探索网页分类
这个数据分析问题的设计目的是识别网站网页的类别,基于页面的访问次数,可以将其按受欢迎程度分为高、中或低(常规)。在设计数据分析生命周期的数据需求阶段时,我们将看到如何从Google Analytics收集这些类型的数据。

确定问题
由于这是一个网页分析问题,该问题的目标是识别为网站设计的网页的重要性。基于这些信息,可以改善或增加较不受欢迎页面的内容、设计或访问量。
设计数据需求
在这一部分,我们将处理该数据分析问题的数据需求和数据收集。首先,让我们看看如何为该问题实现数据需求。
由于这是一个网页分析问题,我们将使用 Google Analytics 数据源。要从 Google Analytics 中提取这些数据,我们需要有一个现有的 Google Analytics 账户,并且该账户上存储有网页流量数据。为了增加受欢迎度,我们将需要所有网页的访问信息。此外,Google Analytics 中还提供了许多与维度和指标相关的其他属性。
理解所需的 Google Analytics 数据属性
从 Google Analytics 提取的数据集的表头格式如下:
date, source, pageTitle, pagePath
-
date:这是网页被访问的日期 -
source:这是指向网页的推荐链接 -
pageTitle:这是网页的标题 -
pagePath:这是网页的 URL
数据收集
由于我们将从 Google Analytics 中提取数据,因此我们需要使用 RGoogleAnalytics,这是一个用于在 R 中提取 Google Analytics 数据集的 R 库。要提取数据,您需要先在 R 中安装此插件。然后,您将能够使用其函数。
以下是从 Google Analytics 提取数据的代码:
# Loading the RGoogleAnalytics library
require("RGoogleAnalyics")
# Step 1\. Authorize your account and paste the access_token
query <- QueryBuilder()
access_token <- query$authorize()
# Step 2\. Create a new Google Analytics API object
ga <- RGoogleAnalytics()
# To retrieve profiles from Google Analytics
ga.profiles <- ga$GetProfileData(access_token)
# List the GA profiles
ga.profiles
# Step 3\. Setting up the input parameters
profile <- ga.profiles$id[3]
startdate <- "2010-01-08"
enddate <- "2013-08-23"
dimension <- "ga:date,ga:source,ga:pageTitle,ga:pagePath"
metric <- "ga:visits"
sort <- "ga:visits"
maxresults <- 100099
# Step 4\. Build the query string, use the profile by setting its index value
query$Init(start.date = startdate,
end.date = enddate,
dimensions = dimension,
metrics = metric,
max.results = maxresults,
table.id = paste("ga:",profile,sep="",collapse=","),
access_token=access_token)
# Step 5\. Make a request to get the data from the API
ga.data <- ga$GetReportData(query)
# Look at the returned data
head(ga.data)
write.csv(ga.data,"webpages.csv", row.names=FALSE)
上述文件将在章节内容中提供下载。
数据预处理
现在,我们有了 Google Analytics 的原始数据,存储在 CSV 文件中。在将数据提供给 MapReduce 算法之前,我们需要处理这些数据。
需要对数据集进行两项主要更改:
-
需要从
pagePath列中移除查询参数,如下所示:pagePath <- as.character(data$pagePath) pagePath <- strsplit(pagePath,"\\?") pagePath <- do.call("rbind", pagePath) pagePath <- pagePath [,1] -
需要创建新的 CSV 文件,如下所示:
data <- data.frame(source=data$source, pagePath=d,visits =) write.csv(data, "webpages_mapreduce.csv" , row.names=FALSE)
执行数据分析
为了对网站页面进行分类,我们将构建并运行与 R 和 Hadoop 集成的 MapReduce 算法。正如在第二章《编写 Hadoop MapReduce 程序》中已讨论的那样,编写 Hadoop MapReduce 程序,有时我们需要使用多个 Mappers 和 Reducers 来执行数据分析;这意味着需要使用链式 MapReduce 任务。
在链式 MapReduce 任务中,多个 Mappers 和 Reducers 可以通过某种方式进行通信,使得第一个任务的输出作为第二个任务的输入。MapReduce 执行顺序如下图所示:

链式 MapReduce
现在让我们开始编程任务以执行分析:
-
通过设置 Hadoop 变量并加载 RHadoop 库中的
rmr2和rhdfs包来初始化:# setting up the Hadoop variables need by RHadoop Sys.setenv(HADOOP_HOME="/usr/local/hadoop/") Sys.setenv(HADOOP_CMD="/usr/local/hadoop/bin/hadoop") # Loading the RHadoop libraries rmr2 and rhdfs library(rmr2) library(rhdfs) # To initializing hdfs hdfs.init() -
上传数据集到 HDFS:
# First uploading the data to R console, webpages <- read.csv("/home/vigs/Downloads/webpages_mapreduce.csv") # saving R file object to HDFS, webpages.hdfs <- to.dfs(webpages)
现在我们将看到这些分析的 Hadoop MapReduce 任务 1 的开发过程。我们将这个任务分为 Mapper 和 Reducer。由于有两个 MapReduce 任务,因此将有两个 Mappers 和 Reducers。还需要注意的是,我们只需要为两个任务创建一个文件,包含所有的 Mappers 和 Reducers。Mapper 和 Reducer 将通过定义它们各自的函数来建立。
让我们来看一下 MapReduce 任务 1。
-
Mapper 1:代码如下:
mapper1 <- function(k,v) { # To storing pagePath column data in to key object key <- v[2] # To store visits column data into val object Val <- v[3] # emitting key and value for each row keyval(key, val) } totalvisits <- sum(webpages$visits) -
Reducer 1:代码如下:
reducer1 <- function(k,v) { # Calculating percentage visits for the specific URL per <- (sum(v)/totalvisits)*100 # Identify the category of URL if (per <33 ) { val <- "low" } if (per >33 && per < 67) { val <- "medium" } if (per > 67) { val <- "high" } # emitting key and values keyval(k, val) } -
MapReduce 任务 1 的输出:信息的中间输出如下截图所示:
![执行数据分析]()
上述截图中的输出仅为 MapReduce 任务 1 的输出信息。这可以视为一个中间输出,其中仅考虑了整个数据集中的 100 行数据来提供输出。在这些行中,23 个 URL 是唯一的;因此,输出提供了 23 个 URL。
让我们看看 Hadoop MapReduce 任务 2:
-
Mapper 2:代码如下:
#Mapper: mapper2 <- function(k, v) { # Reversing key and values and emitting them keyval(v,k) } -
Reducer 2:代码如下:
key <- NA val <- NULL # Reducer: reducer2 <- function(k, v) { # for checking whether key-values are already assigned or not. if(is.na(key)) { key <- k val <- v } else { if(key==k) { val <- c(val,v) } else{ key <- k val <- v } } # emitting key and list of values keyval(key,list(val)) }提示
在执行 MapReduce 作业之前,请启动所有 Hadoop 守护进程,并通过
hdfs.init()方法检查 HDFS 连接。如果您的 Hadoop 守护进程尚未启动,可以通过$hduser@ubuntu :~ $HADOOP_HOME/bin/start-all.sh启动它们。
一旦我们准备好 Mapper 和 Reducer 的逻辑,就可以通过 rmr2 包中的 MapReduce 方法执行 MapReduce 作业。在这里,我们开发了多个 MapReduce 作业,因此我们需要在 mapreduce 函数内调用 mapreduce 函数,并传入所需的参数。
调用链式 MapReduce 作业的命令如下图所示:

以下是从 HDFS 检索生成的输出的命令:
from.dfs(output)
在执行 Hadoop MapReduce 时,执行日志输出将打印到终端,用于监控目的。我们将通过将 MapReduce 作业 1 和 MapReduce 作业 2 分成不同的部分来理解它们。
MapReduce 作业 1 的详细信息如下:
-
跟踪 MapReduce 作业元数据:通过这部分初始日志,我们可以识别 Hadoop MapReduce 作业的元数据。我们还可以通过调用给定的
Tracking URL使用浏览器跟踪作业状态。![对数据执行分析]()
-
跟踪 Mapper 和 Reducer 任务的状态:通过这部分日志,我们可以监控在 Hadoop 集群上运行的 Mapper 或 Reducer 任务的状态,获取任务是否成功或失败等详细信息。
![对数据执行分析]()
-
跟踪 HDFS 输出位置:一旦 MapReduce 作业完成,其输出位置将在日志末尾显示。
![对数据执行分析]()
对于 MapReduce 作业 2。
-
跟踪 MapReduce 作业元数据:通过这部分初始日志,我们可以识别 Hadoop MapReduce 作业的元数据。我们还可以通过调用给定的
Tracking URL使用浏览器跟踪作业状态。![对数据执行分析]()
-
跟踪 Mapper 和 Reducer 任务的状态:通过这部分日志,我们可以监控在 Hadoop 集群上运行的 Mapper 或 Reducer 任务的状态,获取任务是否成功或失败等详细信息。
![对数据执行分析]()
-
跟踪 HDFS 输出位置:一旦 MapReduce 作业完成,其输出位置将在日志末尾显示。
![对数据执行分析]()
这个链式 MapReduce 作业的输出存储在 HDFS 位置,可以通过以下命令检索:
from.dfs(output)
前述命令的响应如下图所示(仅显示数据集前 1000 行的输出):

数据可视化
我们使用三个类别收集了网页分类输出。我认为我们最好的做法是简单地列出这些 URL。但如果我们有更多的信息,比如来源,我们可以将网页表示为一个图的节点,通过用户跟随链接的有向边来标记其流行度。这可以带来更多有价值的见解。
计算股票市场变化的频率
这个数据分析 MapReduce 问题旨在计算股票市场变化的频率。
确定问题
由于这是一个典型的股票市场数据分析问题,它将计算某一特定符号的股票市场过去变动的频率,比如傅里叶变换。基于这些信息,投资者可以获得关于不同时间段变化的更多见解。因此,这次分析的目标是计算百分比变化的频率。

设计数据需求
对于本次股票市场分析,我们将使用 Yahoo! Finance 作为输入数据集。我们需要检索特定符号的股票信息。为此,我们将使用 Yahoo! API,传递以下参数:
-
从某月开始
-
从某天开始
-
从某年开始
-
到某月
-
到某天
-
到某年
-
符号
提示
有关此 API 的更多信息,请访问developer.yahoo.com/finance/。
数据预处理
为了对提取的数据集进行分析,我们将使用 R 来执行以下命令:
stock_BP <- read.csv("http://ichart.finance.yahoo.com/table.csv?s=BP")
或者你也可以通过终端下载:
wget http://ichart.finance.yahoo.com/table.csv?s=BP
#exporting to csv file
write.csv(stock_BP,"table.csv", row.names=FALSE)
然后通过创建一个特定的 Hadoop 目录将其上传到 HDFS:
# creating /stock directory in hdfs
bin/hadoop dfs -mkdir /stock
# uploading table.csv to hdfs in /stock directory
bin/hadoop dfs -put /home/Vignesh/downloads/table.csv /stock/
对数据进行分析
为了执行数据分析操作,我们将使用 R 和 Hadoop 进行流式处理(无需HadoopStreaming包)。因此,这个 MapReduce 作业的开发可以在没有任何 RHadoop 集成库/包的情况下完成。
在这个 MapReduce 作业中,我们已经在不同的 R 文件中定义了 Map 和 Reduce,并将它们提供给 Hadoop streaming 函数。
-
Mapper:
stock_mapper.R#! /usr/bin/env/Rscript # To disable the warnings options(warn=-1) # To take input the data from streaming input <- file("stdin", "r") # To reading the each lines of documents till the end while(length(currentLine <-readLines(input, n=1, warn=FALSE)) > 0) { # To split the line by "," seperator fields <- unlist(strsplit(currentLine, ",")) # Capturing open column value open <- as.double(fields[2]) # Capturing close columns value close <- as.double(fields[5]) # Calculating the difference of close and open attribute change <- (close-open) # emitting change as key and value as 1 write(paste(change, 1, sep="\t"), stdout()) } close(input) -
Reducer:
stock_reducer.R#! /usr/bin/env Rscript stock.key <- NA stock.val <- 0.0 conn <- file("stdin", open="r") while (length(next.line <- readLines(conn, n=1)) > 0) { split.line <- strsplit(next.line, "\t") key <- split.line[[1]][1] val <- as.numeric(split.line[[1]][2]) if (is.na(current.key)) { current.key <- key current.val <- val } else { if (current.key == key) { current.val <- current.val + val } else { write(paste(current.key, current.val, sep="\t"), stdout()) current.key <- key current.val<- val } } } write(paste(current.key, current.val, sep="\t"), stdout()) close(conn)
从以下代码中,我们可以在 R 中运行 MapReduce,而无需安装或使用任何 R 库/包。R 中有一个system()方法,可以在 R 控制台内触发系统命令,帮助我们在 R 中直接启动 Hadoop 作业。它还会将命令的响应提供到 R 控制台。
# For locating at Hadoop Directory
system("cd $HADOOP_HOME")
# For listing all HDFS first level directorysystem("bin/hadoop dfs -ls /")
# For running Hadoop MapReduce with streaming parameters
system(paste("bin/hadoop jar
/usr/local/hadoop/contrib/streaming/hadoop-streaming-1.0.3.jar ",
" -input /stock/table.csv",
" -output /stock/outputs",
" -file /usr/local/hadoop/stock/stock_mapper.R",
" -mapper /usr/local/hadoop/stock/stock_mapper.R",
" -file /usr/local/hadoop/stock/stock_reducer.R",
" -reducer /usr/local/hadoop/stock/stock_reducer.R"))
# For storing the output of list command
dir <- system("bin/hadoop dfs -ls /stock/outputs", intern=TRUE)
dir
# For storing the output from part-oooo (output file)
out <- system("bin/hadoop dfs -cat /stock/outputs/part-00000", intern=TRUE)
# displaying Hadoop MapReduce output data out
你也可以通过终端运行这个相同的程序:
bin/hadoop jar /usr/local/hadoop/contrib/streaming/hadoop-streaming-1.0.3.jar \
-input /stock/table.csv \
-output /stock/outputs\
-file /usr/local/hadoop/stock/stock_mapper.R \
-mapper /usr/local/hadoop/stock/stock_mapper.R \
-file /usr/local/hadoop/stock/stock_reducer.R \
-reducer /usr/local/hadoop/stock/stock_reducer.R
在运行该程序时,R 控制台或终端的输出将如以下截图所示,通过此输出我们可以监控 Hadoop MapReduce 作业的状态。这里我们将按顺序查看这些输出的各个部分。请注意,我们已将日志输出分为几个部分,以帮助您更好地理解。
MapReduce 的日志输出包含(当从终端运行时):
-
使用日志的这部分,我们可以识别 Hadoop MapReduce 作业的元数据。我们还可以通过浏览器通过调用给定的
Tracking URL来跟踪作业状态。这就是 MapReduce 作业元数据的跟踪方式。![数据分析]()
-
使用这部分日志,我们可以监控在 Hadoop 集群上运行的 Mapper 或 Reducer 任务的状态,查看是否成功或失败。这就是我们跟踪 Mapper 和 Reducer 任务状态的方式。
![数据分析]()
-
一旦 MapReduce 作业完成,其输出位置将在日志的最后显示。这就是跟踪 HDFS 输出位置的方式。
![数据分析]()
-
从终端,Hadoop MapReduce 程序的输出可以通过以下命令调用:
bin/hadoop dfs -cat /stock/outputs/part-00000 -
你 MapReduce 程序输出的表头将如下所示:
change frequency -
下图展示了 MapReduce 问题的示例输出:
![数据分析]()
数据可视化
如果我们通过各种图表在 R 中可视化我们的输出,我们可以获得更多的见解。在这里,我们通过ggplot2包尝试可视化输出。

从前面的图表中,我们可以迅速识别出,大部分时间股票价格从 0 附近变动到 1.5。因此,股票历史上的价格波动在投资时会很有帮助。
生成此图所需的代码如下:
# Loading ggplot2 library
library(ggplot2);
# we have stored above terminal output to stock_output.txt file
#loading it to R workspace
myStockData <- read.delim("stock_output.txt", header=F, sep="", dec=".");
# plotting the data with ggplot2 geom_smooth function
ggplot(myStockData, aes(x=V1, y=V2)) + geom_smooth() + geom_point();
在下一部分,我们将介绍如何使用 R 和 Hadoop 进行大数据分析的案例研究,应用于Kaggle数据竞赛。
预测推土机蓝皮书销售价格——案例研究
这是一个案例研究,旨在预测重型设备拍卖销售价格,并为推土机创建蓝皮书。
识别问题
在这个例子中,我包括了 Cloudera 数据科学家的一项案例研究,讲述了如何对大数据集进行重采样,并在 R 和 Hadoop 中应用随机森林模型。在这里,我参考了 Kaggle 推土机蓝皮书竞赛来理解大数据问题定义的类型。该竞赛的目标是根据设备的使用情况、设备类型和配置,预测某一特定重型设备在使用拍卖中的销售价格。这个解决方案由Uri Laserson(Cloudera 的数据科学家)提供。提供的数据包含拍卖结果发布、使用情况和设备配置的信息。
这是一个技巧,用于对大数据集建模并将其划分为较小的数据集。将模型应用于该数据集是传统的机器学习技术,如随机森林或集成方法。随机森林可能有两个原因:
-
大型数据集通常存储在集群中,因此任何操作都将具有一定程度的并行性。不同的模型在不同的节点上拟合,这些节点包含初始数据的不同子集。
-
即使你可以使用整个初始数据集来拟合单个模型,事实证明,集成方法(通过使用数据子集来拟合多个较小的模型)通常优于单一模型。实际上,用 1 亿数据点拟合单个模型的效果可能比用每个包含 1000 万数据点的几个模型要差(即较小的总数据集优于较大的总数据集)。
有放回抽样是从初始数据集中采样以生成样本集合用于模型拟合的最常见方法。该方法等同于从多项分布中抽样,其中选择任何单个输入数据点的概率在整个数据集上是均匀的。
提示
Kaggle 是一个大数据平台,来自全球的数据科学家在这里竞赛,解决由数据驱动的组织主办的大数据分析问题。
设计数据需求
对于本次竞赛,Kaggle 提供了一个包含约 400,000 个训练数据点的真实世界数据集。每个数据点代表了推土机销售、配置以及销售价格的各种属性。为了预测销售价格,随机森林回归模型需要被实现。
注意
该 Kaggle 竞赛的参考链接为 www.kaggle.com/c/bluebook-for-bulldozers。你可以查看数据、信息、论坛和排行榜,还可以探索其他大数据分析竞赛并参与其中,以评估你的数据分析技能。
我们选择这个模型是因为我们有兴趣从一个大型数据集的随机集合中预测销售价格的数值。
数据集以以下数据文件的形式提供:
| 文件名 | 描述格式(大小) |
|---|---|
Train |
这是一个包含 2011 年数据的训练集。 |
Valid |
这是一个验证集,包含 2012 年 1 月 1 日至 2012 年 4 月 30 日的数据。 |
Data dictionary |
这是训练数据集变量的元数据。 |
Machine_Appendix |
这包含了给定机器的正确制造年份,以及品牌、型号和产品类别的详细信息。 |
Test |
这是测试数据集。 |
random_forest_benchmark_test |
这是主办方提供的基准解决方案。 |
提示
如果你想学习和实践大数据分析,可以通过参与 Kaggle 数据竞赛从 Kaggle 数据源获取大数据集。这些数据集来自世界各地不同行业的多个领域。
数据预处理
为了对提供的 Kaggle 数据集执行分析,我们需要构建一个预测模型。为了预测拍卖的销售价格,我们将在提供的数据集上拟合模型。但是数据集提供了多个文件。因此,我们将它们合并,并进行数据增强以获取更有意义的数据。我们将从Train.csv和Machine_Appendix.csv构建模型,以更好地预测销售价格。
下面是需要在数据集上执行的数据预处理任务:
# Loading Train.csv dataset which includes the Sales as well as machine identifier data attributes.
transactions <- read.table(file="~/Downloads/Train.csv",
header=TRUE,
sep=",",
quote="\"",
row.names=1,
fill=TRUE,
colClasses=c(MachineID="factor",
ModelID="factor",
datasource="factor",
YearMade="character",
SalesID="character",
auctioneerID="factor",
UsageBand="factor",
saledate="custom.date.2",
Tire_Size="tire.size",
Undercarriage_Pad_Width="undercarriage",
Stick_Length="stick.length"),
na.strings=na.values)
# Loading Machine_Appendix.csv for machine configuration information
machines <- read.table(file="~/Downloads/Machine_Appendix.csv",
header=TRUE,
sep=",",
quote="\"",
fill=TRUE,
colClasses=c(MachineID="character",
ModelID="factor",
fiManufacturerID="factor"),
na.strings=na.values)
# Updating the values to numeric
# updating sale data number
transactions$saledatenumeric <- as.numeric(transactions$saledate)
transactions$ageAtSale <- as.numeric(transactions$saledate - as.Date(transactions$YearMade, format="%Y"))
transactions$saleYear <- as.numeric(format(transactions$saledate, "%Y"))
# updating the month of sale from transaction
transactions$saleMonth <- as.factor(format(transactions$saledate, "%B"))
# updating the date of sale from transaction
transactions$saleDay <- as.factor(format(transactions$saledate, "%d"))
# updating the day of week of sale from transaction
transactions$saleWeekday <- as.factor(format(transactions$saledate, "%A"))
# updating the year of sale from transaction
transactions$YearMade <- as.integer(transactions$YearMade)
# deriving the model price from transaction
transactions$MedianModelPrice <- unsplit(lapply(split(transactions$SalePrice,
transactions$ModelID), median), transactions$ModelID)
# deriving the model count from transaction
transactions$ModelCount <- unsplit(lapply(split(transactions$SalePrice, transactions$ModelID), length), transactions$ModelID)
# Merging the transaction and machine data in to dataframe
training.data <- merge(x=transactions, y=machines, by="MachineID")
# write denormalized data out
write.table(x=training.data,
file="~/temp/training.csv",
sep=",",
quote=TRUE,
row.names=FALSE,
eol="\n",
col.names=FALSE)
# Create poisson directory at HDFS
bin/hadoop dfs -mkdir /poisson
# Uploading file training.csv at HDFS
bin/hadoop dfs -put ~/temp/training.csv /poisson/
在数据上执行分析
由于我们将使用采样的数据集执行分析,我们需要了解需要对多少个数据集进行采样。
对于随机抽样,我们考虑了三个模型参数,如下所示:
-
我们在初始训练集中有 N 个数据点。这非常大(106-109),分布在一个 HDFS 集群中。
-
我们将为一个集成分类器训练一组 M 个不同的模型。
-
每个 M 个模型将使用 K 个数据点进行拟合,其中通常 K << N。(例如,K 可能是 N 的 1-10%)。
我们有 N 个训练数据集,这些数据集是固定的,通常在我们的控制之外。由于我们将通过泊松抽样来处理这些数据,我们需要定义要输入随机森林模型的总输入向量数。
需要考虑三种情况:
-
KM < N:在这种情况下,我们没有使用我们可用的全部数据量。
-
KM = N:在这种情况下,我们可以完全分割我们的数据集,以生成完全独立的样本。
-
KM > N:在这种情况下,我们必须用替换的方式对部分数据进行重新抽样。
在下一节中描述的泊松抽样方法在相同的框架内处理所有三种情况。但是请注意,对于 KM = N 的情况,它不会对数据进行分区,而只是重新抽样。
理解泊松近似重采样
广义线性模型是一般线性模型的扩展。泊松回归是广义模型的一种情况。因变量服从泊松分布。
泊松抽样将在 MapReduce 任务的 Map 上运行,因为它发生在输入数据点上。这并不保证每个数据点都将被考虑到模型中,但它比全数据集的多项式重新抽样更好。但它将通过使用 N 个训练输入点保证生成独立样本。
在这里,下图显示了在泊松抽样中可以检索到的遗漏数据集的数量,其功能为 KM/N:

灰线指示了 KM=N 的值。现在,让我们看看 MapReduce 算法的伪代码。我们使用了三个参数:N、M 和 K,其中 K 是固定的。我们使用 T=K/N 来消除先验值 N 的需求。
-
采样参数的示例:在这里,我们将用伪代码实现前述逻辑。首先,我们将定义两个模型输入参数
frac.per.model和num.models,其中frac.per.model用于定义可以使用的完整数据集的比例,而num.models用于定义将从数据集中拟合的模型数量。T = 0.1 # param 1: K / N-average fraction of input data in each model 10% M = 50 # param 2: number of models -
Mapper 的逻辑:Mapper 将被设计为通过数据整理生成完整数据集的样本。
def map(k, v): // for each input data point for i in 1:M // for each model m = Poisson(T) // num times curr point should appear in this sample if m > 0 for j in 1:m // emit current input point proper num of times emit (i, v) -
Reducer 的逻辑:Reducer 将接受一个数据样本作为输入,并对其进行随机森林模型的拟合。
def reduce(k, v): fit model or calculate statistic with the sample in v
使用 RHadoop 拟合随机森林
在机器学习中,拟合模型意味着将最佳的线拟合到我们的数据中。拟合模型有几种类型,分别是欠拟合、过拟合和正常拟合。在欠拟合和过拟合的情况下,可能会出现较高的偏差(交叉验证和训练误差高)和较高的方差(交叉验证误差高但训练误差低)的影响,这是不理想的。我们通常会对数据集进行模型拟合。
下面是拟合模型的三种拟合类型的示意图:
-
欠拟合:在这种情况下,交叉验证和训练误差较高
![Fitting random forests with RHadoop]()
-
正常拟合:在这种情况下,交叉验证和训练误差是正常的
![Fitting random forests with RHadoop]()
-
过拟合:在这种情况下,交叉验证误差较高但训练误差较低
![Fitting random forests with RHadoop]()
我们将使用机器学习中的随机森林技术对数据进行拟合。这是一种递归划分方法,特别适用于大规模和小规模问题。它涉及一组(或集合)分类(或回归)树,这些树是通过在数据的随机子集上计算得出的,每个分类树的每次分割都使用一个随机选择和限制的预测变量子集。
此外,使用分类/回归树集成的结果已经被用于生成比使用单一分类树更好的预测。
我们将使用 RHadoop 实现我们的泊松采样策略。首先,我们会为参数设置全局值:
#10% of input data to each sample on avg
frac.per.model <- 0.1
num.models <- 50
让我们检查如何按照伪代码的规范,使用 RHadoop 实现 Mapper。
-
Mapper 的实现方式如下:
poisson.subsample <- function(k, input) { # this function is used to generate a sample from the current block of data generate.sample <- function(i) { # generate N Poisson variables draws <- rpois(n=nrow(input), lambda=frac.per.model) # compute the index vector for the corresponding rows, # weighted by the number of Poisson draws indices <- rep((1:nrow(input)), draws) # emit the rows; RHadoop takes care of replicating the key appropriately # and rbinding the data frames from different mappers together for the # reducer keyval(i, input[indices, ]) } # here is where we generate the actual sampled data c.keyval(lapply(1:num.models, generate.sample)) }由于我们使用的是 R,因此在收集的样本数据集上使用随机森林模型拟合模型是一个复杂的过程。
-
Reducer 的实现方式如下:
# REDUCE function fit.trees <- function(k, v) { # rmr rbinds the emitted values, so v is a dataframe # note that do.trace=T is used to produce output to stderr to keep the reduce task from timing out rf <- randomForest(formula=model.formula, data=v, na.action=na.roughfix, ntree=10, do.trace=FALSE) # rf is a list so wrap it in another list to ensure that only # one object gets emitted. this is because keyval is vectorized keyval(k, list(forest=rf)) } -
为了拟合模型,我们需要
model.formula,其内容如下:model.formula <- SalePrice ~ datasource + auctioneerID + YearMade + saledatenumeric + ProductSize + ProductGroupDesc.x + Enclosure + Hydraulics + ageAtSale + saleYear + saleMonth + saleDay + saleWeekday + MedianModelPrice + ModelCount + MfgYearSalePrice定义为响应变量,其他变量定义为随机森林模型的预测变量。提示
R 中的随机森林模型不支持具有超过 32 个级别的因子变量。
-
MapReduce 作业可以通过以下命令执行:
mapreduce(input="/poisson/training.csv", input.format=bulldozer.input.format, map=poisson.subsample, reduce=fit.trees, output="/poisson/output")生成的树被导出到 HDFS 的
/poisson/output路径下。 -
最后,我们可以加载这些树,合并它们,并用它们来分类新的测试点:
mraw.forests <- values(from.dfs("/poisson/output")) forest <- do.call(combine, raw.forests)
每个 50 个样本都生成了一个包含 10 棵树的随机森林,因此最终的随机森林是由 500 棵树组成的,并且以分布式的方式在 Hadoop 集群上进行拟合。
注意
所有源文件的完整集合可以在 Cloudera 官方网站的博客中找到,链接:blog.cloudera.com/blog/2013/02/how-to-resample-from-a-large-data-set-in-parallel-with-r-on-hadoop/。
希望我们已经学习到了一种可扩展的方法,通过使用泊松近似来进行多项式采样,从而以并行方式训练集成分类器或进行自助法(bootstrapping)。
总结
在本章中,我们学习了如何在 R 和 Hadoop 集成环境中,利用各种数据驱动活动进行大数据分析。
在下一章中,我们将学习更多关于如何使用 R 和 Hadoop 来执行机器学习技术的内容。
第六章:使用机器学习理解大数据分析
在本章中,我们将学习不同的机器学习技术,这些技术可以与 R 和 Hadoop 一起使用,以通过以下要点执行大数据分析:
-
机器学习简介
-
机器学习算法类型
-
监督式机器学习算法
-
无监督机器学习算法
-
推荐算法
机器学习简介
机器学习是人工智能的一个分支,它使我们能够在没有显式编程的情况下,使应用程序具备智能。机器学习的概念被用于使应用程序能够从现有数据集中做出决策。机器学习与数据挖掘的结合可以用于开发垃圾邮件检测器、自动驾驶汽车、语音识别、面部识别和在线交易欺诈活动检测等。
有许多知名的组织正在使用机器学习算法,使他们的服务或产品能够理解用户的需求,并根据用户的行为提供服务。谷歌拥有其智能的网页搜索引擎,提供了第一大搜索引擎、Google Mail 中的垃圾邮件分类、Google News 中的新闻标签分类,以及亚马逊的推荐系统。许多开源框架可用于开发这些类型的应用程序/框架,如 R、Python、Apache Mahout 和 Weka。
机器学习算法类型
目前有三种不同类型的机器学习算法,用于智能系统开发:
-
监督式机器学习算法
-
无监督机器学习算法
-
推荐系统
在本章中,我们将讨论一些著名的商业问题,包括分类、回归和聚类,以及如何在 Hadoop 上执行这些机器学习技术,以克服内存问题。
如果你加载的某个数据集无法适应机器的内存,并且你尝试运行它,预测分析将抛出与机器内存相关的错误,例如错误:无法分配大小为 990.1 MB 的向量。解决方案是增加机器配置或使用商品硬件进行并行化。
监督式机器学习算法
在本节中,我们将学习监督式机器学习算法。算法如下:
-
线性回归
-
逻辑回归
线性回归
线性回归主要用于基于历史信息预测和预报值。回归是一个监督式机器学习技术,用于识别目标变量和解释变量之间的线性关系。我们可以说,它用于预测目标变量的数值。
在接下来的章节中,我们将学习如何使用 R 和 Hadoop 进行线性回归。
这里,目标变量是需要预测的变量,帮助预测目标变量的变量称为解释变量。通过线性关系,我们可以识别解释变量变化对目标变量的影响。
在数学中,回归可以如下表示:
y = ax + e
其他公式包括:
-
回归线的斜率由以下公式给出:
a = (NΣxy - (Σx)(Σy)) / (NΣx² - (Σx)²)
-
回归的截距点由以下公式给出:
e = (Σy - b(Σx)) / N
这里,x 和 y 是构成数据集的变量,N 是值的总数。
假设我们有以下表格中的数据:
| x | y |
|---|---|
| 63 | 3.1 |
| 64 | 3.6 |
| 65 | 3.8 |
| 66 | 4 |
如果我们有一个新的 x 值,我们可以通过回归公式获得对应的 y 值。
线性回归的应用包括:
-
销售预测
-
预测最佳产品价格
-
从各种来源和活动中预测下一次在线购买
让我们看看如何使用统计技术来实现提供的数据集的回归模型。假设我们已获得 n 个统计数据单元。

它的公式如下:
Y = e[0] + a[0]x[0] + a[1]x[1] + a[2]x[2] + a[3]x[3] + a[4]x[4]
这里,Y 是目标变量(响应变量),xi 是解释变量,e[0] 是误差项的平方和,可以视为噪声。为了获得更准确的预测,我们需要尽早通过 call 函数减少这个误差项。
使用 R 进行线性回归
现在我们将看看如何在 R 中执行线性回归。我们可以使用内置的 lm() 方法来构建一个线性回归模型。
Model <-lm(target ~ ex_var1, data=train_dataset)
它将基于提供的数据集的属性构建回归模型,并存储所有用于预测和识别数据模式的变量系数和模型参数。
# Defining data variables
X = matrix(rnorm(2000), ncol = 10)
y = as.matrix(rnorm(200))
# Bundling data variables into dataframe
train_data <- data.frame(X,y)
# Training model for generating prediction
lmodel<- lm(y~ train_data $X1 + train_data $X2 + train_data $X3 + train_data $X4 + train_data $X5 + train_data $X6 + train_data $X7 + train_data $X8 + train_data $X9 + train_data $X10,data= train_data)
summary(lmodel)
以下是使用前述 summary 命令可以显示的各种模型参数:
-
RSS:这等于 ∑(y 实际 - y)²。
-
自由度(DOF):用于识别预测模型的拟合度,应该尽可能小(从逻辑上讲,值为 0 表示完美预测)。
-
残差标准误差(RSS/DF):用于识别预测模型的拟合度,应该尽可能小(从逻辑上讲,值为 0 表示完美预测)。
-
pr:这是变量被纳入模型的概率;要将一个变量纳入模型,其值应小于 0.05。
-
t 值:这等于 15。
-
f:这是检查 R 方是否为非零值的统计量。

使用 R 和 Hadoop 进行线性回归
假设我们有一个大型数据集。现在我们如何进行回归数据分析?在这种情况下,我们可以使用 R 和 Hadoop 集成,通过实现 Mapper 和 Reducer 来执行并行线性回归。它将把数据集分配到各个节点之间,然后这些节点将并行处理分布式数据。当我们在 R 和 Hadoop 集群中运行时,它不会引发内存问题,因为大型数据集将被分布式并与 Hadoop 计算节点中的 R 一起处理。同时,请记住,这种实现方法的预测精度不比 lm() 模型高。
RHadoop 用于集成 R 和 Hadoop,它是 Revolution Analytics 的一个受信的开源发行版。如需了解有关 RHadoop 的更多信息,请访问 github.com/RevolutionAnalytics/RHadoop/wiki。在 RHadoop 的软件包中,这里我们只使用 rmr 和 rhdfs 库。
让我们看看如何使用 R 和 Hadoop 数据技术进行回归分析。
# Defining the datasets with Big Data matrix X
X = matrix(rnorm(20000), ncol = 10)
X.index = to.dfs(cbind(1:nrow(X), X))
y = as.matrix(rnorm(2000))
在这里,Sum() 函数是可重用的,如以下代码所示:
# Function defined to be used as reducers
Sum =
function(., YY)
keyval(1, list(Reduce('+', YY)))
线性回归算法的大纲如下:
-
使用 MapReduce 作业 1 计算
Xtx值。 -
使用 MapReduce 作业 2 计算
Xty值。 -
使用
Solve (Xtx, Xty)推导系数值。
让我们逐一理解这些步骤。
第一步是使用 MapReduce 作业 1 计算 Xtx 值。
-
大矩阵以完整行的块传递给 Mapper。这些子矩阵的较小交叉乘积会被计算并传递给单个 Reducer,后者将它们加总在一起。由于我们有一个单一的键,Combiner 是必须的,而且由于矩阵求和具有结合性和交换性,我们当然可以在这里使用它。
# XtX = values( # For loading hdfs data in to R from.dfs( # MapReduce Job to produce XT*X mapreduce( input = X.index, # Mapper – To calculate and emitting XT*X map = function(., Xi) { yi = y[Xi[,1],] Xi = Xi[,-1] keyval(1, list(t(Xi) %*% Xi))}, # Reducer – To reduce the Mapper output by performing sum operation over them reduce = Sum, combine = TRUE)))[[1]] -
当我们有大量数据存储在 Hadoop 分布式文件系统 (HDFS) 中时,我们需要将其路径值传递给
MapReduce方法的输入参数。 -
在前面的代码中,我们看到
X是设计矩阵,它是通过以下函数创建的:X = matrix(rnorm(2000), ncol = 10) -
它的输出将如下所示:
![使用 R 和 Hadoop 进行线性回归]()
所以,这里所有列将被视为解释变量,并且它们的标准误差可以按照与正常线性回归中计算标准误差的相同方式来计算。
计算 Xty 值与 MapReduce 作业 2 基本相同,向量 y 会根据正常作用域规则在各节点中可用。
Xty = values(
# For loading hdfs data
from.dfs(
# MapReduce job to produce XT * y
mapreduce(
input = X.index,
# Mapper – To calculate and emitting XT*y
map = function(., Xi) {
yi = y[Xi[,1],]
Xi = Xi[,-1]
keyval(1, list(t(Xi) %*% yi))},
# Reducer – To reducer the Mapper output by performing # sum operation over them
reduce = Sum,
combine = TRUE)))[[1]]
要推导系数值,使用 solve (Xtx, Xty),请按照以下步骤操作:
-
最后,我们只需要调用以下代码行来获取系数值。
solve(XtX, Xty) -
前面的命令的输出将如下所示:
![使用 R 和 Hadoop 进行线性回归]()
逻辑回归
在统计学中,逻辑回归或 logit 回归是一种概率分类模型。逻辑回归在许多学科中广泛应用,包括医学和社会科学领域。它可以是二项式或多项式。
二元逻辑回归处理因变量结果可能有两种可能类型的情况。多项式逻辑回归处理结果可能有三种或更多类型的情况。
逻辑回归可以使用逻辑函数实现,这里列出了它们。
-
要预测对数几率比,请使用以下公式:
logit(p) = β0 + β1 × x1 + β2 × x2 + ... + βn × xn
-
概率公式如下:
p = e^(logit(p)) ⁄ 1 + e^(logit(p))
logit(p)是解释变量 X(x1,x2,x3..xn)的线性函数,类似于线性回归。因此,该函数的输出将在 0 到 1 的范围内。根据概率分数,我们可以将其概率范围设置为 0 到 1。在大多数情况下,如果分数大于 0.5,则视为 1,否则为 0。此外,我们可以说它为分类结果提供了分类边界。

上述图是一个训练数据集。基于训练数据集的绘图,我们可以说glm模型在 R 中生成了一个分类边界。
逻辑回归的应用包括:
-
预测在线购买的可能性
-
检测糖尿病的存在
使用 R 进行逻辑回归
要使用 R 执行逻辑回归,我们将使用iris数据集和glm模型。
#loading iris dataset
data(iris)
# Setting up target variable
target <- data.frame(isSetosa=(iris$Species == 'setosa'))
# Adding target to iris and creating new dataset
inputdata <- cbind(target,iris)
# Defining the logistic regression formula
formula <- isSetosa ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width
# running Logistic model via glm()
logisticModel <- glm(formula, data=inputdata, family="binomial")
使用 R 和 Hadoop 进行逻辑回归
要使用 R 和 Hadoop 执行逻辑回归,我们将使用rmr2和 RHadoop。
逻辑回归算法的大纲如下:
-
定义
lr.map映射函数 -
定义
lr.reducer减少函数 -
定义
logistic.regressionMapReduce 函数
让我们逐一理解它们。
我们将首先定义梯度下降的逻辑回归函数。可以通过将非依赖变量形成矩阵数据格式来执行多变量回归。对于因子变量,我们可以将它们转换为二元变量以适应模型。此函数将要求input,iterations,dims和alpha作为输入参数。
-
lr.map:这代表逻辑回归映射器,将计算子集点对梯度的贡献。# Mapper – computes the contribution of a subset of points to the gradient. lr.map = function(., M) { Y = M[,1] X = M[,-1] keyval( 1, Y * X * g(-Y * as.numeric(X %*% t(plane))))} -
lr.reducer:这代表逻辑回归减少器,仅执行键 1 所有值的总和。# Reducer – Perform sum operation over Mapper output. lr.reduce = function(k, Z) keyval(k, t(as.matrix(apply(Z,2,sum)))) -
logistic.regression:这将主要定义logistic.regressionMapReduce 函数,并带有以下输入参数。调用此函数将开始执行 MapReduce 函数的逻辑回归。-
input: 这是一个输入数据集。 -
iterations: 这是计算梯度的固定迭代次数。 -
dims:这是输入变量的维度 -
alpha:这是学习率
-
让我们看看如何开发逻辑回归函数。
# MapReduce job – Defining MapReduce function for executing logistic regression
logistic.regression =
function(input, iterations, dims, alpha){
plane = t(rep(0, dims))
g = function(z) 1/(1 + exp(-z))
for (i in 1:iterations) {
gradient =
values(
from.dfs(
mapreduce(
input,
map = lr.map,
reduce = lr.reduce,
combine = T)))
plane = plane + alpha * gradient }
plane }
让我们按如下方式运行这个逻辑回归函数:
# Loading dataset
data(foodstamp)
# Storing data to hdfs
testdata <- to.dfs(as.matrix(foodstamp))
# Running logistic regression with R and Hadoop
print(logistic.regression(testdata,10,3,0.05))
前述命令的输出结果如下:

无监督机器学习算法
在机器学习中,无监督学习用于从未标记的数据集中发现隐藏的结构。由于数据集是未标记的,因此在评估潜在解决方案时不会出现错误。
无监督机器学习包括几种算法,以下是其中的一些:
-
聚类
-
人工神经网络
-
向量量化
我们将在这里考虑流行的聚类算法。
聚类
聚类是将一组对象分组的任务,使得具有相似特征的对象被分到同一类别,而其他对象则分到不同类别。在聚类中,输入数据集是未标记的;它们需要根据数据结构的相似性进行标记。
在无监督机器学习中,分类技术执行相同的程序,通过提供的输入训练数据集将数据映射到一个类别。这个相应的过程称为聚类(或聚类分析),它通过某种固有相似性的度量将数据分组到不同的类别中;例如,数据点之间的距离。
从下图中,我们可以识别出聚类是基于相似性将对象分组:

R 库中有几种聚类技术,如 k-means、k-medoids、层次聚类和基于密度的聚类。在这些技术中,k-means 是数据科学中广泛使用的聚类算法。该算法要求用户提供聚类的数量作为输入参数。
聚类的应用如下:
-
市场细分
-
社交网络分析
-
组织计算机网络
-
天文数据分析
使用 R 进行聚类
我们在这里考虑k-means方法来实现聚类模型,基于iris输入数据集,只需调用其内置的 R 数据集——iris数据(欲了解更多信息,请访问stat.ethz.ch/R-manual/R-devel/library/datasets/html/iris.html)。在这里我们将看到如何使用 R 执行 k-means 聚类。
# Loading iris flower dataset
data("iris")
# generating clusters for iris dataset
kmeans <- kmeans(iris[, -5], 3, iter.max = 1000)
# comparing iris Species with generated cluster points
Comp <- table(iris[, 5], kmeans$cluster)
对于小型数据集,推导聚类是相当简单的,但对于大型数据集,推导聚类需要使用 Hadoop 来提供计算能力。
使用 R 和 Hadoop 进行聚类
由于 k-means 聚类算法已经在 RHadoop 中开发完成,我们将使用并理解它。您可以根据输入数据集格式修改它们的 Mappers 和 Reducers。由于我们正在处理 Hadoop,因此需要开发 Mappers 和 Reducers,以便在节点上并行运行。
聚类算法的概述如下:
-
定义
dist.fun距离函数 -
定义
k-means.mapk-means Mapper 函数 -
定义
k-means.reducek-means Reducer 函数 -
定义
k-means.mrk-means MapReduce 函数 -
定义要提供给聚类算法的输入数据点
现在我们将通过提供所需的参数运行k-means.mr(k-means MapReduce 作业)。
让我们逐一理解它们。
-
dist.fun:首先,我们将查看dist.fun函数,该函数用于计算中心矩阵C与点矩阵P之间的距离。它经过测试后,能够在大约 16 秒内生成 10⁶个点和 10²个中心(5 维)。# distance calculation function dist.fun = function(C, P) { apply( C, 1, function(x) colSums((t(P) - x)²))} -
k-means.map:k-means MapReduce 算法的 Mapper 将计算点与所有中心之间的距离,并返回每个点的最近中心。这个 Mapper 将根据以下代码进行迭代运行。在第一次迭代中,聚类中心将被随机分配,从下一次迭代开始,它将根据与聚类中所有点的最小距离计算这些聚类中心。# k-Means Mapper kmeans.map = function(., P) { nearest = { # First interations- Assign random cluster centers if(is.null(C)) sample( 1:num.clusters, nrow(P), replace = T) # Rest of the iterations, where the clusters are assigned # based on the minimum distance from points else { D = dist.fun(C, P) nearest = max.col(-D)}} if(!(combine || in.memory.combine)) keyval(nearest, P) else keyval(nearest, cbind(1, P))} -
k-means.reduce:k-means MapReduce 算法的 Reducer 将计算矩阵点的列平均值作为键。# k-Means Reducer kmeans.reduce = { # calculating the column average for both of the # conditions if (!(combine || in.memory.combine) ) function(., P) t(as.matrix(apply(P, 2, mean))) else function(k, P) keyval( k, t(as.matrix(apply(P, 2, sum))))} -
kmeans.mr:定义 k-means MapReduce 函数涉及指定几个输入参数,具体如下:-
P:表示输入数据点。 -
num.clusters:这是总的聚类数量。 -
num.iter:这是处理数据集的总迭代次数。 -
combine:这将决定是否启用 Combiner(TRUE或FALSE)。# k-Means MapReduce – for kmeans.mr = function( P, num.clusters, num.iter, combine, in.memory.combine) { C = NULL for(i in 1:num.iter ) { C = values( # Loading hdfs dataset from.dfs( # MapReduce job, with specification of input dataset, # Mapper and Reducer mapreduce( P, map = kmeans.map, reduce = kmeans.reduce))) if(combine || in.memory.combine) C = C[, -1]/C[, 1] if(nrow(C) < num.clusters) { C = rbind( C, matrix( rnorm( (num.clusters - nrow(C)) * nrow(C)), ncol = nrow(C)) %*% C) }} C}
-
-
定义要提供给聚类算法的输入数据点:
# Input data points P = do.call( rbind, rep( list( # Generating Matrix of matrix( # Generate random normalized data with sd = 10 rnorm(10, sd = 10), ncol=2)), 20)) + matrix(rnorm(200), ncol =2) -
通过提供所需参数运行
kmeans.mr(k-means MapReduce 作业)。# Running kmeans.mr Hadoop MapReduce algorithms with providing the required input parameters kmeans.mr( to.dfs(P), num.clusters = 12, num.iter = 5, combine = FALSE, in.memory.combine = FALSE) -
上述命令的输出显示在以下截图中:
![使用 R 和 Hadoop 进行聚类]()
推荐算法
推荐是机器学习技术,用于预测用户可能喜欢的新项目,基于用户与之前项目的关联。推荐广泛应用于电子商务领域。通过这种灵活的数据和行为驱动算法,企业可以通过确保在正确的时间向正确的客户自动推荐相关选择,从而增加转化率,实现交叉销售或追加销售。
例如,当一个客户在亚马逊上寻找三星 Galaxy S IV/S4 手机时,商店还会建议其他类似的手机,这些手机会出现在购买此商品的客户还购买了窗口中。
有两种不同类型的推荐:
-
基于用户的推荐:在这种类型中,将确定与当前用户(客户)相似的用户(客户)。基于这种用户相似性,他们感兴趣/使用的物品可以推荐给其他用户。让我们通过一个例子来学习它。
![推荐算法]()
假设有两个用户,Wendell 和 James,他们有相似的兴趣,因为两人都在使用 iPhone。Wendell 使用了两种物品:iPad 和 iPhone,所以 James 会被推荐使用 iPad。这是基于用户的推荐。
-
基于项目的推荐:在这种类型中,将确定与用户当前使用的项目相似的项目。基于项目相似度分数,将向用户展示类似的项目,以进行交叉销售和向上销售类型的推荐。让我们通过一个例子来学习它。
![推荐算法]()
例如,一个名为 Vaibhav 的用户喜欢并使用以下几本书:
-
《Apache Mahout 秘籍》,Piero Giacomelli,Packt Publishing
-
《Hadoop MapReduce 秘籍》,Thilina Gunarathne 和 Srinath Perera,Packt Publishing
-
《Hadoop 真实世界解决方案秘籍》,Brian Femiano,Jon Lentz 和 Jonathan R. Owens,Packt Publishing
-
《大数据入门》,Dr. Fern Halper,Judith Hurwitz,Marcia Kaufman 和 Alan Nugent,John Wiley & Sons Publishers
基于上述信息,推荐系统将预测 Vaibhav 会喜欢阅读哪些新书,如下所示:
- 《大数据分析与 R 与 Hadoop》,Vignesh Prajapati,Packt Publishing
现在我们将了解如何使用 R 和 Hadoop 生成推荐。但是,在讲解 R 和 Hadoop 的结合之前,首先让我们看看如何用 R 来生成推荐。这将帮助你理解如何将生成的推荐系统转换为 MapReduce 推荐算法。在使用 R 和 Hadoop 生成推荐时,我们将使用Revolution Analytics的 RHadoop 分发版。
在 R 中生成推荐的步骤
为了生成用户推荐,我们需要具有特定格式的数据集,算法可以读取这些数据。在这里,我们将使用协同过滤算法来生成推荐,而不是基于内容的算法。因此,我们需要用户对可用项目集的评分信息。因此,small.csv数据集采用user ID, item ID, item's ratings格式。
# user ID, item ID, item's rating
1, 101, 5.0
1, 102, 3.0
1, 103, 2.5
2, 101, 2.0
2, 102, 2.5
2, 103, 5.0
2, 104, 2.0
3, 101, 2.0
3, 104, 4.0
3, 105, 4.5
3, 107, 5.0
4, 101, 5.0
4, 103, 3.0
4, 104, 4.5
4, 106, 4.0
5, 101, 4.0
5, 102, 3.0
5, 103, 2.0
5, 104, 4.0
5, 105, 3.5
5, 106, 4.0
上述代码和数据集摘自《Mahout in Action》一书,作者为Robin Anil、Ellen Friedman、Ted Dunning和Sean Owen,由 Manning Publications 出版,网址为www.fens.me/。
推荐可以通过矩阵分解技术推导出来,如下所示:
Co-occurrence matrix * scoring matrix = Recommended Results
为了生成推荐系统,我们将遵循以下步骤:
-
计算共现矩阵。
-
建立用户评分矩阵。
-
生成推荐。
从下一部分开始,我们将看到执行前述步骤的技术细节。
-
在第一部分中,计算共现矩阵时,我们能够识别数据集中给定的共现物品集。简单来说,我们可以称之为从给定数据集中计数物品对。
# Quote plyr package library (plyr) # Read dataset train <-read.csv (file = "small.csv", header = FALSE) names (train) <-c ("user", "item", "pref") # Calculated User Lists usersUnique <-function () { users <-unique (train $ user) users [order (users)] } # Calculation Method Product List itemsUnique <-function () { items <-unique (train $ item) items [order (items)] } # Derive unique User Lists users <-usersUnique () # Product List items <-itemsUnique () # Establish Product List Index index <-function (x) which (items %in% x) data<-ddply(train,.(user,item,pref),summarize,idx=index(item)) # Co-occurrence matrix Co-occurrence <-function (data) { n <-length (items) co <-matrix (rep (0, n * n), nrow = n) for (u in users) { idx <-index (data $ item [which(data$user == u)]) m <-merge (idx, idx) for (i in 1: nrow (m)) { co [m$x[i], m$y[i]] = co[m$x[i], m$y[i]]+1 } } return (co) } # Generate co-occurrence matrix co <-co-occurrence (data) -
为了基于用户评分信息建立用户评分矩阵,可以为用户生成用户-物品评分矩阵。
# Recommendation algorithm recommend <-function (udata = udata, co = coMatrix, num = 0) { n <- length(items) # All of pref pref <- rep (0, n) pref[udata$idx] <-udata$pref # User Rating Matrix userx <- matrix(pref, nrow = n) # Scoring matrix co-occurrence matrix * r <- co %*% userx # Recommended Sort r[udata$idx] <-0 idx <-order(r, decreasing = TRUE) topn <-data.frame (user = rep(udata$user[1], length(idx)), item = items[idx], val = r[idx]) # Recommended results take months before the num if (num> 0) { topn <-head (topn, num) } # Recommended results take months before the num if (num> 0) { topn <-head (topn, num) } # Back to results return (topn) } -
最终,可以通过两个矩阵项的产品操作生成输出推荐:共现矩阵和用户评分矩阵。
# initializing dataframe for recommendations storage recommendation<-data.frame() # Generating recommendations for all of the users for(i in 1:length(users)){ udata<-data[which(data$user==users[i]),] recommendation<-rbind(recommendation,recommend(udata,co,0)) }
提示
通过Myrrix和 R 接口生成推荐非常简单。更多信息,请参考github.com/jwijffels/Myrrix-R-interface。
使用 R 和 Hadoop 生成推荐
为了使用 R 和 Hadoop 生成推荐,我们需要开发一个能够并行执行和处理数据的算法。这可以通过使用 Mappers 和 Reducers 来实现。该部分的一个非常有趣的部分是我们如何将 R 和 Hadoop 结合使用,从大数据集生成推荐。
所以,以下步骤类似于使用 R 生成推荐,但将其转换为 Mapper 和 Reducer 范式有些复杂:
-
建立共现矩阵项。
-
将用户评分矩阵建立到文章中。
-
生成推荐。
我们将使用与之前在 R 中生成推荐相同的概念来结合 R 和 Hadoop 生成推荐。但在这种情况下,我们需要使用键值对范式,因为它是并行操作的基础。因此,每个函数都将通过考虑键值对范式来实现。
-
在第一部分中,建立共现矩阵项时,我们将按照步骤建立共现项:按用户分组,定位每个用户选择的单独出现物品计数,以及配对计数。
# Load rmr2 package library (rmr2) # Input Data File train <-read.csv (file = "small.csv", header = FALSE) names (train) <-c ("user", "item", "pref") # Use the hadoop rmr format, hadoop is the default setting. rmr.options (backend = 'hadoop') # The data set into HDFS train.hdfs = to.dfs (keyval (train$user, train)) # see the data from hdfs from.dfs (train.hdfs)需要注意的要点是:
-
train.mr:这是 MapReduce 任务的键值对范式信息 -
key:这是物品列表向量
-
value:这是物品组合向量
# MapReduce job 1 for co-occurrence matrix items train.mr <-mapreduce ( train.hdfs, map = function (k, v) { keyval (k, v$item) } # for identification of co-occurrence items , Reduce = function (k, v) { m <-merge (v, v) keyval (m$x, m$y) } )共现矩阵项将被组合以进行计数。
为了定义一个 MapReduce 任务,使用
step2.mr来计算物品组合的频率。-
Step2.mr:这是 MapReduce 任务的键值对范式信息 -
key:这是物品列表向量
-
value:这是共现矩阵数据框的值(
item,item,Freq)
# MapReduce function for calculating the frequency of the combinations of the items. step2.mr <-mapreduce ( train.mr, map = function (k, v) { d <-data.frame (k, v) d2 <-ddply (d,. (k, v), count) key <- d2$k val <- d2 keyval(key, val) } ) # loading data from HDFS from.dfs(step2.mr) -
-
为了将用户评分矩阵建立到文章中,让我们定义
Train2.mrMapReduce 任务。# MapReduce job for establish user scoring matrix to articles train2.mr <-mapreduce ( train.hdfs, map = function(k, v) { df <- v # key as item key <-df $ item # value as [item, user pref] val <-data.frame (item = df$item, user = df$user, pref = df$pref) # emitting (key, value)pairs keyval(key, val) } ) # loading data from HDFS from.dfs(train2.mr)-
Train2.mr:这是 MapReduce 任务的键值对范式信息 -
key:这是物品列表
-
value:这是用户商品评分矩阵的值
以下是合并和共现评分矩阵:
# Running equi joining two data – step2.mr and train2.mr eq.hdfs <-equijoin ( left.input = step2.mr, right.input = train2.mr, map.left = function (k, v) { keyval (k, v) }, map.right = function (k, v) { keyval (k, v) }, outer = c ("left") ) # loading data from HDFS from.dfs (eq.hdfs)-
eq.hdfs:这是 MapReduce 任务的键值对范式信息 -
key:这里的键是空的
-
value:这是合并的数据框值
-
-
在生成推荐的部分,我们将获取推荐结果的列表。
# MapReduce job to obtain recommended list of result from equijoined data cal.mr <-mapreduce ( input = eq.hdfs, map = function (k, v) { val <-v na <-is.na (v$user.r) if (length (which(na))> 0) val <-v [-which (is.na (v $ user.r)),] keyval (val$kl, val) } , Reduce = function (k, v) { val <-ddply (v,. (kl, vl, user.r), summarize, v = freq.l * pref.r) keyval (val $ kl, val) } ) # loading data from HDFS from.dfs (cal.mr)-
Cal.mr: 这是 MapReduce 作业的键值范式信息 -
key: 这是项目列表
-
value: 这是推荐结果数据框的值
通过定义用于获取带有优先级值的推荐项目列表的结果,将对推荐结果进行排序处理。
# MapReduce job for sorting the recommendation output result.mr <-mapreduce ( input = cal.mr, map = function (k, v) { keyval (v $ user.r, v) } , Reduce = function (k, v) { val <-ddply (v,. (user.r, vl), summarize, v = sum (v)) val2 <-val [order (val$v, decreasing = TRUE),] names (val2) <-c ("user", "item", "pref") keyval (val2$user, val2) } ) # loading data from HDFS from.dfs (result.mr)-
result.mr: 这是 MapReduce 作业的键值范式信息 -
key: 这是用户 ID
-
value: 这是推荐结果数据框的值
-
在这里,我们设计了用于生成基于项目推荐的协同算法。由于我们尝试使其在并行节点上运行,我们重点关注了 Mapper 和 Reducer。它们在某些情况下可能不是最优的,但你可以通过使用现有代码使其变得最优。
总结
在这一章中,我们学习了如何借助 R 和 Hadoop 技术利用机器学习进行大数据分析。在下一章,我们将学习如何通过将 R 与各种外部数据源集成来丰富数据集。
第七章 从各种数据库导入和导出数据
在本章的最后,我们将看到如何将来自不同来源的数据加载到 R 中,以执行数据分析操作。在这里,我们考虑了一些流行的数据库,它们被用作数据存储,支持不同应用和技术下的分析操作。如我们所知,使用 R 执行分析操作相较于其他分析工具非常简单,而且 R 是免费的、开源的。由于 R 可以通过安装 R 包使用自定义函数,CRAN 上有许多数据库包可供与 R 连接使用。因此,R 编程语言因其数据库独立性以及操作系统独立性,越来越受欢迎。
我们特别设计了本章,旨在分享如何将来自不同数据库系统的数据加载到 R 中进行数据建模。我们在本章中包括了多个流行的数据库示例,用于执行各种数据库操作。
我们已经覆盖了与 R 一起使用的各种流行数据源。它们如下:
-
RData
-
MySQL
-
Excel
-
MongoDB
-
SQLite
-
PostgreSQL
-
Hive
-
HBase

从上面的图表中,我们可以理解到,R 支持多种数据库系统,可以在不同的数据库上执行与数据分析相关的操作。由于 R 有大量的库可以连接各种数据库,我们只需要继承它们即可。
在下面的表格中,列出了常见的数据库系统及其相关的 R 包,以便更容易理解相关的 R 包:
| 数据库系统名称 | 有用的 R 包 / 函数工具 |
|---|---|
| 文本文件 | 文本数据文件,如.csv、.txt和.r |
| MySQL | RMySQL |
| Excel | Xlsx |
| Mongo | RMongo |
| SQLlite | RSQLlite |
| PostgreSQL | RPostgreSQL |
| HDFS | RHDFS |
| Hive | RHive |
| HBase | RHBase |
正如我们所知,提到的每个数据库都有其独特的重要性和功能。为了更好地理解,每个数据源都将通过以下几点进行描述:
-
介绍
-
特性
-
安装
-
将数据导入到 R 中
-
数据操作
-
从 R 导出数据
在本章中,我们将安装并使用 R 包,这些包将用于 R 中的各种数据操作。
现在,我们将开始了解数据库以及如何执行与数据相关的操作,以便为所有数据库的后续数据分析做准备。
学习数据文件作为数据库
在进行数据分析活动时,我们需要不断进行数据导入、加载或导出功能。有时,可能需要使用 R 编程语言反复执行相同的操作。因此,我们可以使用 R 的现有函数来执行相同的数据操作。
理解不同类型的文件
常用的 R 数据存储操作文件有四种不同的类型。它们如下:
-
CSV(逗号分隔值)
-
Txt(带有制表符分隔值)
-
.RDATA(R 的本地数据格式)
-
.rda(R 的本地数据格式)
安装 R 包
要使用之前指定格式的数据文件,我们不需要额外安装 R 包。我们只需要使用 R 提供的内置函数。
将数据导入 R
要执行与分析相关的活动,我们需要使用以下函数将数据导入 R:
-
CSV:
read.csv()用于读取 逗号分隔值(CSV)文件,其中小数点是","。检索到的数据将存储到一个 R 对象中,这被视为Dataframe。Dataframe <- read.csv("data.csv",sep=",") -
TXT:要检索制表符分隔的值,
read.table()函数将与一些重要参数一起使用,该函数的返回类型将是Dataframe 类型。Dataframe <- read.table("data.csv", sep="\t") -
.RDATA:此处,.RDATA 格式由 R 用于存储特定时间段的工作区数据。它被视为图像文件。这将存储/检索工作区中所有可用的数据。
load("history.RDATA") -
.rda:这也是 R 的本地数据格式,根据需要存储特定的数据变量。
load("data_variables_a_and_b.rda")
从 R 导出数据
要从 R 导出现有的数据对象并支持按要求的数据文件,我们需要使用以下函数:
-
CSV:通过以下命令将 dataframe 对象写入
csv数据文件:write.csv(mydata, "c:/mydata.csv", sep=",", row.names=FALSE) -
TXT:通过以下命令将数据写入带有制表符分隔符的数据文件:
write.table(mydata, "c:/mydata.txt", sep="\t") -
.RDATA:要存储可用于 R 会话的工作区数据变量,请使用以下命令:
save.image() -
.rda:此函数用于存储特定的数据对象,供以后使用。使用以下代码将它们保存到
.rda文件中。# column vector a <- c(1,2,3) # column vector b <- c(2,4,6) # saving it to R (.rda) data format save(a, b, file=" data_variables_a_and_b.rda")
理解 MySQL
MySQL 是世界上最流行的开源数据库。世界上许多最大和发展最快的组织,包括 Facebook、Google、Adobe 和 Zappos,都依赖 MySQL 数据库,以节省时间和金钱,支持高流量的网站、关键业务系统和软件包。
由于 R 和 MySQL 都是开源的,它们可以用于构建交互式网页分析应用程序。同时,借助这个独特的包,也可以对现有的网页应用程序进行简单的数据分析。
要在 Linux 机器上安装 MySQL,您需要按照以下步骤顺序进行操作:
-
安装 MySQL
-
安装 RMySQL
安装 MySQL
我们将看到如何在 Linux 上安装 MySQL:
// Updating the linux package list
sudo apt-get update
// Upgrading the updated packages
sudo apt-get dist-upgrade
//First, install the MySQL server and client packages:
sudo apt-get install mysql-server mysql-client
提示
使用以下命令登录到 MySQL 数据库:
mysql -u root -p
安装 RMySQL
现在,我们已经在 Linux 机器上安装了 MySQL。是时候通过以下 R 命令从 CRAN 安装 RMySQL 库:
# to install RMySQL library
install.packages("RMySQL")
#Loading RMySQL
library(RMySQL)
在 RMySQL 库安装在 R 上后,通过提供 MySQL 管理控制台中提供的用户权限,执行 MySQL 数据库连接:
mydb = dbConnect(MySQL(), user='root', password='', dbname='sample_table', host='localhost')
学习列出表格及其结构
现在,数据库连接已成功完成。要列出 MySQL 数据库中可用的表及其数据结构,可以查看以下命令。要返回 mydb 数据库下创建的可用表,请使用以下命令:
dbListTables(mydb)
要返回在 sample_table 表中创建的数据字段列表,请使用以下命令:
dbListFields(mydb, 'sample_table')
将数据导入到 R 中
我们知道如何检查 MySQL 表及其字段。在识别出有用的数据表后,我们可以使用以下 RMySQL 命令将其导入 R 中。为了根据提供的 SQL 查询从 MySQL 数据库中检索自定义数据,我们需要将其存储在一个对象中:
rs = dbSendQuery(mydb, "select * from sample_table")
可用的数据相关信息可以通过以下 fetch 命令从 MySQL 获取到 R 中:
dataset = fetch(rs, n=-1)
在此,指定参数 n = -1 用于检索所有待处理的记录。
理解数据操作
要执行 MySQL 数据库的数据操作,我们需要执行 SQL 查询。但在 RMySQL 的情况下,我们可以通过 dbSendQuery 函数执行命令。
使用现有的 R 数据框在 MySQL 数据库中创建新表可以通过以下命令完成:
dbWriteTable(mydb, name='mysql_table_name', value=data.frame.name)
要将 R 矩阵数据插入到 MySQL 中现有的数据表,可以使用以下命令:
# defining data matrix
datamatrix <- matrix(1:4, 2, 2)
# defining query to insert the data
query <- paste("INSERT INTO names VALUES(",datamatrix [1,1], ",", datamatrix [1,2], ")")
# command for submitting the defined SQL query dbGetQuery(con, query)
有时候,当 MySQL 表不再使用时,我们需要删除它。可以执行以下查询来删除 mysql_some_table 表:
dbSendQuery(mydb, 'drop table if exists mysql_some_table').
理解 Excel
Excel 是由微软开发的一款电子表格应用程序,支持在 Windows 和 Mac OS 上运行,具有类似于 R 的功能,用于执行统计计算、图形可视化和数据建模。Excel 是微软在 Microsoft Office 套件中提供的,主要支持 .xls 电子表格数据文件格式。如果我们希望从 R 中读取或写入 Microsoft Excel 电子表格,可以使用许多可用的 R 包。但其中一个流行且有效的 R 库是 xlsx。
该包通过编程方式提供对 Excel 文件的控制,允许用户将 .xlsx 文档的电子表格读取到 data.frame 中,并将 data.frame 写入文件。该包是由 Adrian A. Dragulescu 开发的。
安装 Excel
在这里,我们将 .xls 文件作为数据源,可以借助 Microsoft Excel 97/2000/XP/2003 来构建和维护该文件。
以下是 xlsx 包的前提条件:
-
xlsxjars
-
rJava
安装 xlsxX 包:
-
Install.packages("xlsxjars")
-
Install.packages("rJava")
-
Install.packages("xlsx")
将数据导入到 R 中
假设我们已经创建了一个 Excel 文件,现在我们希望在 R 中执行与数据分析相关的操作,那么这个包是将 Excel 文件加载到 R 中进行处理的最佳选择。
es <- read.xlsx("D:/ga.xlsx",1)
前面的命令将把 Excel 数据(带有工作表 1)存储到 R 中的 es 数据框格式。
理解 R 和 Excel 中的数据操作
以下命令将用于选择数据框res的子集,其中选择前五行:
r <- res[1:5,]
将数据导出到 Excel
根据定义的名称,处理后的数据可以以xls文件格式存储,支持 Excel。
ress <- write.xlsx(r, "D:/ga1.xls")
理解 MongoDB
MongoDB 是一种基于 NoSQL 的分布式文档数据存储。它特别设计用于提供可扩展且高性能的数据存储解决方案。在许多场景中,它可以用来替代传统的关系型数据库或键值数据存储。Mongo 的最大特点是其查询语言,非常强大,语法与面向对象的查询语言有些相似。
以下是 MongoDB 的特点:
-
面向集合的存储,易于存储对象类型
-
支持动态查询
-
完整的索引支持
-
丰富的查询语言
-
数据碎片处理顺序以支持云级扩展
-
基于 BSON 的文件数据存储
-
支持 C、C++、C#、Erlang、Haskell、Java、JavaScript、Perl、PHP、Python、Ruby 和 Scala
我们可以通过安装以下先决条件,将 R 和 MongoDB 一起使用:
-
MongoDB 安装
-
rmongodb 安装
安装 MongoDB
以下是在 Ubuntu 12.04 和 CentOS 中安装 MongoDB 的步骤:
首先,我们将看到 Ubuntu 的安装步骤。
-
使用以下命令配置软件包管理系统(APT):
sudo apt-key adv --keyserverhkp://keyserver.ubuntu.com:80 --recv 7F0CEB10 -
使用以下命令创建
/etc/apt/sources.list.d/mongodb.list:echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list -
现在,使用以下命令更新您的操作系统软件包列表:
sudo apt-get update -
使用以下命令安装 MongoDB 的最新版本:
apt-get install mongodb-10gen
现在,我们将看到 CentOS 的安装步骤。
-
配置软件包管理系统(YUM)。
-
创建
/etc/yum.repos.d/mongodb.repo并使用以下配置:-
对于 64 位系统,请使用以下命令:
[mongodb] name=MongoDB Repository baseurl=http://downloads-distro.mongodb.org/repo/redhat/os/x86_64/ gpgcheck=0 enabled=1 -
对于 32 位系统,请使用以下命令:
[mongodb] name=MongoDB Repository baseurl=http://downloads-distro.mongodb.org/repo/redhat/os/i686/ gpgcheck=0 enabled=1
-
-
安装软件包。
使用以下命令,安装 MongoDB 的稳定版本及相关工具:
yum install mongo-10gen mongo-10gen-server
现在,您已成功安装 MongoDB。
提示
用于控制 mongodb 服务的有用命令
要启动 mongodb 服务,我们使用以下命令:
sudo service mongodb start
要停止 mongodb 服务,我们使用以下命令:
sudo service mongodb stop
要重启 mongodb 服务,我们使用以下命令:
sudo service mongodb restart
要启动 Mongo 控制台,我们使用以下命令:
mongo
SQL 映射到 MongoDB
以下是 SQL 术语与 MongoDB 术语的映射,帮助更好地理解数据存储:
| 序号 | SQL 术语 | MongoDB 术语 |
|---|---|---|
| 1. | 数据库 | 数据库 |
| 2. | 表 | 集合 |
| 3. | 索引 | 索引 |
| 4. | 行 | 文档 |
| 5. | 列 | 字段 |
| 6. | 加入 | 嵌入与链接 |
SQL 映射到 MongoQL
以下是 SQL 语句与 Mongo QL 语句的映射,帮助理解查询开发/转换:
| 序号 | SQL 语句 | Mongo QL 语句 |
|---|---|---|
| 1. |
INSERT INTO students VALUES(1,1)
|
$db->students->insert(array("a" => 1, "b" => 1));
|
| 2. |
|---|
SELECT a, b FROM students
|
$db->students->find(array(), array("a" => 1, "b" => 1));
|
| 3. |
|---|
SELECT * FROM students WHERE age < 15
|
$db->students->find(array("age" => array('$lt' => 15)));
|
| 4. |
|---|
UPDATE students SET a=1 WHERE b='q'
|
$db->students->update(array("b" => "q"), array('$set' => array("a" => 1)));
|
| 5. |
|---|
DELETE FROM students WHERE name="siddharth"
|
$db->students->remove(array("name" => " siddharth"));
|
安装 rmongodb
要在 R 中使用 MongoDB,我们需要安装带有 rmongodb 库的 R。我们可以通过以下命令从 CRAN 安装 rmongodb:
# installing library rmongodb in R
install.packages (rmongodb)
将数据导入 R
我们已经学习了如何在 Ubuntu 12.04 上安装 MongoDB。现在,我们可以对数据执行所有必要的操作。在本节中,我们将学习如何在 R 中处理和导入 Mongo 数据进行数据分析活动。加载库时,我们使用以下命令:
# loading the library of rmongodb
library (rmongodb)
Mongo connection establishment
mongo <-mongo.create ()
Check whether the normal series
mongo.is.connected (mongo)
Create a BSON object cache
buf <- mongo.bson.buffer.create ()
Add element to the object buf
mongo.bson.buffer.append (buf, "name", "Echo")
mongo.bson 类的对象用于存储 BSON 文档。BSON 是 MongoDB 用来在其数据库中存储文档的格式。MongoDB 的网络流量也使用 BSON 消息:
b <- mongo.bson.from.list(list(name="Fred", age=29, city="Boston"))iter <- mongo.bson.iterator.create(b) # b is of class "mongo.bson"while (mongo.bson.iterator.next(iter))print(mongo.bson.iterator.value(iter))
了解数据操作
现在我们将看到如何在 R 中操作 Mongo 数据对象:
# To check whether mongo is connected or not in R.
if (mongo.is.connected(mongo)) {ns <- "test.people"
#Returns a fresh mongo.bson.buffer object ready to have data
#appended onto it in R.buf <- mongo.bson.buffer.create()mongo.bson.buffer.append(buf, "name", "Joe")criteria <- mongo.bson.from.buffer(buf)
# mongo.bson.buffer objects are used to build mongo.bson objects.buf <- mongo.bson.buffer.create()
mongo.bson.buffer.start.object(buf, "inc")mongo.bson.buffer.append(buf, "age", 1L)mongo.bson.buffer.finish.object(buf)objNew <- mongo.bson.from.buffer(buf)# increment the age field of the first record matching name "Joe"mongo.update(mongo, ns, criteria, objNew)
# mongo.bson.buffer objects are used to build mongo.bson objects.buf <- mongo.bson.buffer.create()mongo.bson.buffer.append(buf, "name", "Jeff")criteria <- mongo.bson.from.buffer(buf)
# mongo.bson.buffer objects are used to build mongo.bson objects.buf <- mongo.bson.buffer.create()mongo.bson.buffer.append(buf, "name", "Jeff")mongo.bson.buffer.append(buf, "age", 27L)objNew <- mongo.bson.from.buffer(buf)# update the entire record to { name: "Jeff", age: 27 }# where name equals "Jeff"# if such a record exists; otherwise, insert this as a new reordmongo.update(mongo, ns, criteria, objNew,mongo.update.upsert)# do a shorthand update:mongo.update(mongo, ns, list(name="John"), list(name="John", age=25))}
了解 SQLite
SQLite 是一个使用 C 编程语言开发的关系型数据库管理系统。SQLite 遵循 ACID 原则,并实现了大部分 SQL 标准。与其他数据库系统不同,SQLite 没有独立的进程来为客户端应用程序提供数据。它是一个嵌入式 SQL 数据库引擎。SQLite 系统直接读取和写入系统磁盘文件,因为它是一个基于文件的数据库。相关的 SQL 数据库包含多个表、索引和视图,并且这种数据库文件格式支持跨平台使用。
快速了解事务的 ACID 属性:
为了执行事务,需要满足一系列属性。它们是原子性、一致性、隔离性和持久性,具体解释如下:
-
原子性指的是数据库所有任务都必须执行的保证。
-
一致性确保数据库始终保持一致状态,就像我们开始之前的状态一样。
-
隔离性指的是在事务期间,其他操作无法访问或查看数据的中间状态。
-
持久性指的是一旦用户收到成功通知,事务将会持久化,不会被撤销。这意味着它能在系统故障后生存,并且数据库系统已检查完整性约束,且不需要中止事务。
了解 SQLite 的特点
以下是遵循 ACID 属性的 SQLite 数据库特性:
-
零配置
-
支持跨平台的磁盘格式
-
比客户端-服务器型数据库系统更快
-
易于使用的 API
使用 SQLite 和 R 一起使用时,我们需要以下先决条件:
-
SQLite 安装
-
安装 RSQLite
安装 SQLite
要在 Ubuntu 中安装 SQLite 数据库,请遵循给定的命令:
// install sqllite by firing the following commands
sudo apt-get purge sqlite3 sqlite3-doc libsqlite3-0
sudo apt-get autoremove
sudo apt-get install sqlite3 sqlite3-doc
安装 RSQLite
我们可以通过以下命令安装 RSQLite:
# installing RSQLite library from CRAN in R
Install.packages("RSQLite")
将数据导入 R
我们将看到如何使用 RSQLite 包将数据插入 R 中。
要加载已安装的包,我们使用以下命令:
#loading the installed package
library("RSQLite")
使用以下命令,您可以连接到数据库并列出所有数据库中的表:
# connect to db
con <- dbConnect(SQLite(), dbname="data/first.db")
# list all tables
tables <- dbListTables(con)
# exclude sqlite_sequence (contains table information)
tables <- tables[tables != "sqlite_sequence"]
lDataFrames <- vector("list", length=length(tables))
# create a data.frame for each table
for (i in seq(along=tables)) {
lDataFrames[[i]] <- dbGetQuery(conn=con, statement=paste("SELECT * FROM '", tables[[i]], "'", sep=""))
}
了解数据操作
我们可以使用以下命令操作数据集:
dbBeginTransaction(con)
rs <- dbSendQuery(con, "DELETE from candidates WHERE age > 50")
Exporting the data from Rdata(USArrests)
dbWriteTable(con, "USArrests", USArrests)
理解 PostgreSQL
PostgreSQL 是一个开源的对象关系型数据库管理系统。PostgreSQL 可以在大多数操作系统上运行,如 Linux、UNIX 和 Windows。它支持文本、图像、声音和视频数据源。它还支持 C、C++、Java、Python、Ruby 和 Tcl 等编程技术。
理解 PostgreSQL 的特性
以下是 PostgreSQL 的特性:
-
复杂 SQL 查询
-
完全符合 ACID 规范
-
SQL 子查询
使用 PostgreSQL 在 R 中时,我们需要安装以下先决条件:
-
安装 PostgreSQL
-
安装 RPostgreSQL
安装 PostgreSQL
在这一节中,我们将学习如何安装 PostgreSQL。
安装 PostgreSQL 时,将按照以下命令进行:
// updating the packages list
Sudo apt-get update
// installing postgresql
sudo apt-get install postgresql postgresql-contrib
// creating postgresql user
su – postgres createuser
安装 RPostgreSQL
现在我们将了解如何安装并使用 RPostgreSQL:
# installing package from CRAN
install.packages(RPostgreSQL)
Importing the data into R# loading the installed package
library(RPostgreSQL)
## load the PostgreSQL driver
drv <- dbDriver("PostgreSQL")
## Open a connection
con <- dbConnect(drv, dbname="oxford")
## Submits a statement
rs <- dbSendQuery(con, "select * from student")
## fetch all elements from the result set
fetch(rs,n=-1)
## Closes the connection
dbDisconnect(con)
## Frees all the resources on the driver
dbUnloadDriver(drv)
使用以下代码,我们将学习如何在 R 中操作存储在 PostgreSQL 中的数据:
opendbGetQuery(con, "BEGIN TRANSACTION")
rs <- dbSendQuery(con,
"Delete * from sales as p where p.cost>10")
if(dbGetInfo(rs, what = "rowsAffected") > 250){
warning("Rolling back transaction")
dbRollback(con)
}else{
dbCommit(con)
}
从 R 中导出数据
在这一节中,我们将学习如何加载数据,将数据框中的内容写入指定的表,并从数据库连接中删除指定的表:
conn <- dbConnect("PostgreSQL", dbname = "wireless")
if(dbExistsTable(con, "frame_fuel")){
dbRemoveTable(conn, "frame_fuel")
dbWriteTable(conn, "frame_fuel", fuel.frame)
}
if(dbExistsTable(conn, "RESULTS")){
dbWriteTable(conn, "RESULTS", results2000, append = T)
else
dbWriteTable(conn, "RESULTS", results2000)
}
理解 Hive
Hive 是一个基于 Hadoop 的数据仓库框架,由 Facebook 开发。它允许用户使用 SQL 查询,并通过 HiveQL 等语言将查询高度抽象化为 Hadoop MapReduce。这使得没有 MapReduce 经验的 SQL 程序员能够使用该数据仓库,并且便于与商业智能和可视化工具集成,实现实时查询处理。
理解 Hive 的特性
以下是 Hive 的特性:
-
Hibernate 查询语言(HQL)
-
支持 UDF
-
元数据存储
-
数据索引
-
不同的存储类型
-
Hadoop 集成
RHive 的先决条件如下:
-
Hadoop
-
Hive
我们假设读者已经配置了 Hadoop;如果没有,他们可以通过 第一章,准备使用 R 和 Hadoop 来学习 Hadoop 的安装。由于运行 RHive 需要 Hive,我们将首先了解如何安装 Hive。
安装 Hive
安装 Hive 的命令如下:
// Downloading the hive source from apache mirror
wget http://www.motorlogy.com/apache/hive/hive-0.11.0/hive-0.11.0.tar.gz
// For extracting the hive source
tar xzvf hive-0.11.0.tar.gz
设置 Hive 配置
要设置 Hive 配置,我们需要通过添加几项内容来更新 hive-site.xml 文件:
-
使用以下命令更新
hive-site.xml文件:<description> JDBC connect string for a JDBC metastore </ description> </Property> <property> <name> javax.jdo.option.ConnectionDriverName </ name> <value> com.mysql.jdbc.Driver </ value> <description> Driver class name for a JDBC metastore </ description> </Property> <property> <name> javax.jdo.option.ConnectionUserName </ name> <value> hive </value> <description> username to use against metastore database </ description> </ Property> <property> <name> javax.jdo.option.ConnectionPassword </name> <value> hive</value> <description> password to use against metastore database </ description> </Property> <property> <name> hive.metastore.warehouse.dir </ name> <value> /user/hive/warehouse </value> <description> location of default database for the warehouse </ description> </Property> -
通过添加以下行来更新
hive-log4j.properties:log4j.appender.EventCounter = org.apache.hadoop.log.metrics.EventCounter -
使用以下命令更新环境变量:
export $HIVE_HOME=/usr/local/ hive-0.11.0 -
在 HDFS 中,为 Hive 创建特定目录:
$HADOOP_HOME/bin/ hadoop fs-mkidr /tmp $HADOOP_HOME/bin/ hadoop fs-mkidr /user/hive/warehouse $HADOOP_HOME/bin/ hadoop fs-chmod g+w / tmp $HADOOP_HOME/bin/ hadoop fs-chmod g+w /user/hive/warehouse提示
要启动 Hive 服务器,需要从
HIVE_HOME执行hive --service hiveserver命令。
安装 RHive
-
使用以下命令安装依赖库
rjava:// for setting up java configuration variables sudo R CMD javareconf // Installing rJava package install.packages ("rJava") // Installing RHive package from CRAN install.packages("RHive") // Loading RHive library library("RHive")
理解 RHive 操作
我们将了解如何使用 RHive 库在 R 中加载并操作 Hive 数据集:
-
初始化 RHive 时,我们使用:
rhive.init () -
要连接到 Hive 服务器,我们使用:
rhive.connect ("192.168.1.210") -
要查看所有表,我们使用:
rhive.list.tables () tab_name 1 hive_algo_t_account 2 o_account 3 r_t_account -
要查看表结构,我们使用:
rhive.desc.table ('o_account'); col_name data_type comment 1 id int 2 email string 3 create_date string -
执行 HQL 查询时我们使用:
rhive.query ("select * from o_account"); -
关闭与 Hive 服务器的连接时我们使用:
rhive.close()
理解 HBase
Apache HBase 是一个分布式大数据存储系统,适用于 Hadoop。它允许对大数据进行随机、实时的读写访问。该系统设计为面向列的数据存储模型,灵感来自于 Google Bigtable。
理解 HBase 的特性
以下是 HBase 的特性:
-
使用 XML 的 RESTful web 服务
-
线性和模块化的可扩展性
-
严格一致的读写操作
-
可扩展的 shell
-
用于实时查询的块缓存和布隆过滤器
RHBase 的前提条件如下:
-
Hadoop
-
HBase
-
Thrift
在这里我们假设用户已经为其 Linux 机器配置了 Hadoop。如果有人想了解如何在 Linux 上安装 Hadoop,请参考 第一章,准备使用 R 和 Hadoop。
安装 HBase
以下是安装 HBase 的步骤:
-
下载 HBase 的 tar 文件并解压:
wget http://apache.cs.utah.edu/hbase/stable/hbase-0.94.11.tar.gz tar -xzf hbase-0.94.11.tar.gz -
进入 HBase 安装目录并更新配置文件:
cd hbase-0.94.11/ vi conf/hbase-site.xml -
修改配置文件:
-
更新
hbase-env.sh。~ Vi conf / hbase-env.sh -
设置 HBase 配置:
export JAVA_HOME = /usr/lib/jvm/java-6-sun export HBASE_HOME = /usr/local/hbase-0.94.11 export HADOOP_INSTALL = /usr/local/hadoop export HBASE_CLASSPATH = /usr/local/hadoop/conf export HBASE_MANAGES_ZK = true -
更新
hbase-site.xmlzxml:Vi conf / hbase-site.xml -
修改
hbase-site.cml,其内容应类似于以下代码:<configuration> <property> <name> hbase.rootdir </name> <value> hdfs://master:9000/hbase </value> </Property> <property> <name>hbase.cluster.distributed </name> <value>true</value> </Property> <property> <name>dfs.replication </name> <value>1</value> </Property> <property> <name>hbase.zookeeper.quorum </name> <value>master</value> </Property> <property> <name>hbase.zookeeper.property.clientPort </name> <value>2181</value> </Property> <property> <name>hbase.zookeeper.property.dataDir </name> <value>/root/hadoop/hdata</value> </Property> </ Configuration>提示
如果使用了独立的 Zookeeper 配置,则需要更改配置。
-
复制 Hadoop 环境配置文件和库文件。
Cp $HADOOP_HOME/conf/hdfs-site.xml $HBASE_HOME/conf Cp $HADOOP_HOME/hadoop-core-1.0.3.jar $HBASE_HOME/lib Cp $HADOOP_HOME/lib/commons-configuration-1.6.jar $HBASE_HOME/lib Cp $HADOOP_HOME/lib/commons-collections-3.2.1.jar $HBASE_HOME/lib
-
安装 thrift
以下是安装 thrift 的步骤:
-
从网上下载 thrift 源码并将其放置到客户端。我们将使用 Ubuntu O.S 12.04 来完成此操作:
get http://archive.apache.org/dist/thrift/0.8.0/thrift-0.8.0.tar.gz -
使用以下命令解压下载的
.tar.gz文件:tar xzvf thrift-0.8.0.tar.gz cd thrift-0.8.0/ -
编译配置参数:
./Configure -
安装 thrift:
Make Make install提示
启动 HBase thrift 服务器时,我们需要调用以下命令:
$HBASE_HOME/bin/hbase-daemon.sh start
安装 RHBase
安装 HBase 后,我们将展示如何获取 RHBase 库。
-
安装
rhbase时使用以下命令:wget https://github.com/RevolutionAnalytics/rhbase/blob/master/build/rhbase_1.2.0.tar.gz -
使用以下命令安装下载的包:
R CMD INSTALL rhbase_1.2.0.tar.gz
将数据导入到 R 中
一旦 RHBase 安装完成,我们可以借助 RHBase 将数据集从 HBase 加载到 R 中:
-
列出所有表时我们使用:
hb.list.tables () -
创建新表时我们使用:
hb.new.table ("student") -
显示表结构时我们使用:
hb.describe.table("student_rhbase") -
读取数据时我们使用:
hb.get ('student_rhbase', 'mary')
理解数据操作
现在,我们将展示如何在 R 中操作 HBase 数据集:
-
创建表时我们使用:
hb.new.table ("student_rhbase", "info") -
插入数据时我们使用:
hb.insert ("student_rhbase", list (list ("mary", "info: age", "24"))) -
删除表时我们使用:
hb.delete.table ('student_rhbase')
总结
在本章中,我们学习了如何将与各种数据库系统和其数据集集成的 R 包加载到 R 中进行数据分析。大多数流行的数据库系统都提供了 R 包,用于加载数据、更新数据以及查询数据以进行分析。
附录 A. 参考文献
在本附录中,提供了与所有章节内容相关的额外资源。
R + Hadoop 帮助材料
-
大数据大学
-
名称:大数据大学
-
类型:在线课程
-
用于:Hadoop 及其组件
-
-
机器学习的在线 Coursera 课程
-
名称:机器学习
-
类型:在线 Coursera 课程
-
作者:Andrew Ng 博士
-
用于:Hadoop 及其组件
-
-
介绍数据科学的在线 Coursera 课程
-
名称:数据科学入门
-
类型:在线 Coursera 课程
-
作者:Bill Howe 博士
-
用于:学习数据操作和分析
-
-
RHadoop
-
名称:RHadoop
-
类型:RHadoop 参考资料
-
用于:RHadoop 包下载
-
-
RHIPE
-
名称:RHIPE
-
URL:
www.datadr.org/ -
类型:RHIPE 参考资料
-
用于:RHIPE 包下载
-
-
HadoopStreaming
-
名称:HadoopStreaming
-
URL:
cran.r-project.org/web/packages/HadoopStreaming/index.html -
类型:RHadoop 包参考资料
-
用于:HadoopStreaming 包下载
-
-
R 文档
-
名称:R 文档
-
类型:在线 R 字典
-
用于:R 文档
-
-
Revolution Analytics
-
名称:Revolution Analytics
-
类型:关于 R 和 Hadoop 的按需网络研讨会
-
用于:R 和 Hadoop 在大型行业中商业应用的重要性
-
R 组
-
使用 R 进行大数据分析
-
名称:使用 R 进行大数据分析(Facebook 小组)
-
类型:Facebook 知识共享小组
-
Hadoop 组
-
Hadoop 实战
-
名称:Hadoop 实战(Facebook 小组)
-
类型:Facebook 知识共享和商业背景
-
-
Hadoop
-
名称:Hadoop(Facebook 小组)
-
类型:Facebook 知识共享
-
-
使用 R 进行大数据分析
-
名称:Hadoop 用户(LinkedIn 小组)
-
类型:用于建立专业联系以及商业背景的 LinkedIn 小组
-
-
Hadoop 邮件列表
-
名称:Hadoop 用户(LinkedIn 小组)
-
类型:用于建立专业联系以及商业背景的 LinkedIn 小组
-
R + Hadoop 组
-
www.fens.me 由 Conan Z 提供贡献,参与了 第六章,理解大数据分析与机器学习,为本书中的推荐系统(使用 R 和 Mahout)和 Hadoop 提供支持
-
名称:Fens.me
-
类型:关于 R、Hadoop 及其组件和其他开源技术的博客集合
-
知名 R 贡献者
-
RStudio
-
名称:RStudio
-
类型:R 社区的软件、教育与服务
-
贡献:Rstudio IDE、plyr、Shiny、RPubs 和 devtools
-
-
R-Bloggers
-
名称:R-Bloggers
-
类型:R 社区的软件、教育与服务
-
贡献:R 博客门户
-
-
Decisionstats
-
名称:Decisionstats
-
类型:使用 R 进行商业分析
-
贡献:商业分析
-
-
RDataMining
-
名称:RDataMining
-
类型:使用 R 进行数据挖掘
-
贡献:使用 R 进行数据挖掘和机器学习,rdatamining
-
-
Hadley Wickham
-
名称:Hadley Wickham
-
网址:
had.co.nz/ -
类型:使用 R 进行数据可视化和统计分析
-
贡献:ggplot2、plyr、testhat、reshape2 和 R 笔记
-
知名 Hadoop 贡献者
-
迈克尔·诺尔(Michael Noll),为本书中关于 Hadoop 安装步骤做出贡献
-
名称:Michael Noll
-
类型:大数据与 Hadoop
-
贡献:开发 Hadoop 和大数据的标准安装步骤和创新项目
-
-
Revolution Analytics
-
名称:Revolution Analytics
-
类型:大数据分析
-
用途:为大企业提供 R 和 Hadoop 大数据分析(RHadoop)
-
-
Hortonworks
-
名称:Hortonworks
-
类型:企业级 Hadoop 解决方案
-
用途:Hadoop、Linux 和 Windows 的 100% 开源及企业级分发
-
贡献:Windows 支持和 YARN
-
-
Cloudera
-
名称:Cloudera
-
类型:企业级 Hadoop 解决方案
-
用途:100% 开源的大数据软件
-
贡献:Sqoop
-
-
Yahoo!
-
名称:Yahoo!
-
类型:企业级 Hadoop 解决方案
-
用途:大数据开源软件
-
贡献:Hadoop 开发由 Yahoo! 和 OOZIE 发起
-





























浙公网安备 33010602011771号