原文:
zh.annas-archive.org/md5/622C4EC47FAAB3CE38900F0C3C942E11
译者:飞龙
前言
本书介绍了与企业中使用的大数据相关的广泛主题。大数据是一个广阔的领域,涵盖了技术、统计、可视化、商业智能以及许多其他相关学科的要素。为了从数据中获得真正的价值,通常由于数据量或技术限制而无法访问,公司必须在软件和硬件层面上利用适当的工具。
因此,本书不仅涵盖了大数据的理论和实践方面,还通过高层次的主题,如企业中的大数据使用、大数据和数据科学计划以及资源、硬件/软件堆栈等关键考虑因素,补充了信息。这些讨论对计划实施或升级组织大数据和/或数据科学平台的组织的 IT 部门将是有用的。
本书重点关注三个主要领域:
1. 大规模数据集上的数据挖掘
今天,大数据是无处不在的,就像不久前的“数据仓库”一样无所不在。行业中有无数的解决方案。特别是 Hadoop 及其生态系统中的产品已经在企业中变得受欢迎且越来越普遍。此外,更近期的创新,如 Apache Spark,也在企业中找到了永久的存在——Hadoop 客户意识到他们可能不需要 Hadoop 框架的复杂性,已经大量转向 Spark。最后,NoSQL 解决方案,如 MongoDB、Redis、Cassandra 以及 Teradata、Vertica 和 kdb+等商业解决方案已经取代了更传统的数据库系统。
本书将以相当深度涵盖这些领域。已经涵盖了 Hadoop 及其相关产品,如 Hive、HBase、Pig Latin 等。我们还涵盖了 Spark,并解释了 Spark 中的关键概念,如操作和转换。还涵盖了诸如 MongoDB 和 KDB+等 NoSQL 解决方案,并提供了实际操作的教程。
2. 机器学习和预测分析
已涵盖的第二个主题是机器学习,也被称为预测分析、统计学习等其他各种名称。提供了使用 R 和 R 中的机器学习包编写的相应机器学习代码的详细解释。已讨论了诸如随机森林、支持向量机、神经网络、随机梯度提升、决策树等算法。此外,还涵盖了机器学习中的关键概念,如偏差和方差、正则化、特征选择、数据预处理等。
3. 企业中的数据挖掘
一般来说,涵盖理论主题的书籍很少讨论大数据的更高层次方面,比如成功的大数据计划的关键要求。本书包括 IT 高管的调查结果,并突出了行业共同的需求。本书还包括了如何根据大型 IT 部门部署生产解决方案的经验教训,逐步指南选择正确的用例,无论是用于大数据还是基于机器学习的内容。
我们相信,凭借对这三个领域的扎实基础知识,任何从业者都可以成功交付大数据和/或数据科学项目。这是本书整体结构和内容的主要意图。
这本书适合谁
本书面向各种受众群体。特别是那些渴望全面了解大数据、数据科学和/或机器学习概念的读者,即它们如何相互关联,将从本书中获益最多。
技术受众:对于技术方面的读者,本书包含了大数据和机器学习的关键行业工具的详细解释。涵盖了使用 Hadoop 进行实践练习,使用 R 编程语言开发机器学习用例,以及使用 R Shiny 构建全面的生产级仪表板。还包括了 Spark 和 NoSQL 的其他教程。除了实践方面,还解释了这些关键技术的理论基础。
商业受众:对大数据的广泛理论和实践处理已经补充了围绕在工作场所部署和实施强大大数据解决方案的微妙问题的高层主题。IT 管理、CIO 组织、业务分析和其他负责定义围绕数据的企业战略的团体将发现这些信息非常有用和直接适用。
本书内容
第一章《大数据的初步介绍》涵盖了大数据和机器学习的基本概念以及使用的工具,并对大数据分析的一般理解进行了介绍。
第二章《大数据挖掘入门》介绍了企业大数据挖掘的概念,并介绍了企业大数据的软件和硬件架构堆栈。
第三章《分析工具包》讨论了用于大数据和机器学习的各种工具,并提供了关于用户可以下载和安装工具(如 R、Python 和 Hadoop)的逐步说明。
第四章《使用 Hadoop 的大数据》介绍了 Hadoop 的基本概念,并深入探讨了 Hadoop 生态系统的详细技术方面。解释了 Hadoop 的核心组件,如 Hadoop 分布式文件系统(HDFS)、Hadoop Yarn、Hadoop MapReduce 以及 Hadoop 2 中的概念,如 ResourceManager、NodeManger、Application Master。该章节还包括了使用 Cloudera Distribution of Hadoop(CDH)通过 Hive 的逐步教程。
第五章《使用 NoSQL 进行大数据分析》介绍了各种新兴和独特的数据库解决方案,通常被称为 NoSQL,它颠覆了关系数据库的传统模型。我们将讨论 NoSQL 的核心概念和技术方面。本节涵盖了各种类型的 NoSQL 系统,如内存型、列式、基于文档、键值、图形等。还包括了与 MongoDB 和 MongoDB Compass 界面相关的教程,以及一个关于使用 kdb+创建生产级 R Shiny 仪表板的非常全面的教程。
第六章《大数据分析的 Spark》介绍了如何使用 Spark 进行大数据分析。涵盖了高层概念和技术主题。涵盖了 SparkContext、有向无环图、操作和转换等关键概念。还提供了关于在 Databricks 上使用 Spark 的完整教程,这是一个用户可以利用 Spark 的平台。
第七章《机器学习概念的初步介绍》介绍了机器学习的基本概念。此外,还讨论了监督学习与无监督学习、分类、回归、特征工程、数据预处理和交叉验证等核心概念。该章节以使用 R 库进行神经网络的简要教程结束。
第八章《机器学习深入探讨》深入探讨了机器学习的一些更深入的方面。算法、偏差、方差、正则化以及机器学习中的各种其他概念都得到了深入讨论。该章还包括了随机森林、支持向量机、决策树等算法的解释。该章以创建基于 Web 的机器学习应用程序的全面教程结束。
第九章《企业数据科学》讨论了部署企业级数据科学和大数据解决方案的技术考虑因素。我们还将讨论全球企业实施大数据战略的各种方式,包括基于云的解决方案。该章还提供了使用 AWS - 亚马逊网络服务的分步教程。
第十章《关于大数据的结束思考》讨论了企业大数据和数据科学战略,并以一些关于如何使大数据相关项目成功的指针结束。
附录 A《大数据进一步阅读》包含了更广泛理解大数据的链接。
为了充分利用本书
-
对 Unix 的一般知识将非常有帮助,尽管不是强制性的
-
需要使用连接到互联网的计算机才能下载练习中使用的必要工具和软件
-
没有假设先前对主题领域的知识
-
所有软件和工具的安装说明都在第三章《分析工具包》中提供。
下载示例代码文件
您可以从www.packtpub.com的帐户中下载本书的示例代码文件。如果您在其他地方购买了本书,可以访问www.packtpub.com/support并注册,文件将直接发送到您的邮箱。
您可以按照以下步骤下载代码文件:
-
登录或注册www.packtpub.com。
-
选择“支持”选项卡。
-
单击“代码下载和勘误”。
-
在搜索框中输入书名,然后按照屏幕上的说明操作。
下载文件后,请确保使用最新版本的解压缩或提取文件夹:
-
Windows 上的 WinRAR/7-Zip
-
Mac 上的 Zipeg/iZip/UnRarX
-
Linux 上的 7-Zip/PeaZip
该书的代码包也托管在 GitHub 上,网址为github.com/PacktPublishing/Practical-Big-Data-Analytics
。我们还有其他代码包来自我们丰富的图书和视频目录,可以在**github.com/PacktPublishing/
**上找到。去看看吧!
下载彩色图片
我们还提供了一个 PDF 文件,其中包含本书中使用的屏幕截图/图表的彩色图片。您可以在这里下载:www.packtpub.com/sites/default/files/downloads/PracticalBigDataAnalytics_ColorImages.pdf
。
使用的约定
本书中使用了许多文本约定。
CodeInText
:表示文本中的代码词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 句柄。例如:“结果存储在 HDFS 的/user/cloudera/output
下。”
代码块设置如下:
"_id" : ObjectId("597cdbb193acc5c362e7ae97"),
"firstName" : "Nina",
"age" : 53,
"frequentFlyer" : [
"Delta",
"JetBlue",
"Delta"
任何命令行输入或输出都以以下形式书写:
$ cd Downloads/ # cd to the folder where you have downloaded the zip file
粗体:表示新术语、重要词汇或屏幕上看到的词语。例如,菜单或对话框中的词语会在文本中以这种方式出现。例如:“这种额外开销可以通过使用虚拟机(VMs)轻松减轻。”
警告或重要说明会以这种形式出现。
提示和技巧会出现在这样。
第一章:太大还是不太大
大数据分析包括与大规模数据集的挖掘、分析和预测建模相关的各种功能。信息的快速增长和技术发展为世界各地的个人和企业提供了独特的机会,以利润和开发新能力,利用大规模分析重新定义传统的商业模式。本章旨在提供大数据显著特征的简要概述,为后续章节打下基础,后续章节将更深入地探讨大数据分析的各个方面。
总的来说,本书将提供行业中使用的大数据分析系统的理论和实践经验。本书以讨论大数据和大数据相关平台(如 Hadoop、Spark 和 NoSQL 系统)开始,然后是机器学习,其中将涵盖实际和理论主题,并最后对行业中大数据和更一般地数据科学的使用进行彻底分析。本书将包括以下主题:
-
大数据平台:Hadoop 生态系统和 Spark NoSQL 数据库,如 Cassandra 高级平台,如 KDB+
-
机器学习:基本算法和概念 使用 R 和 Python 中的 scikit-learn C/C++和 Unix 中的高级工具 现实世界中的神经网络机器学习 大数据基础设施
-
AWS(亚马逊网络服务)企业云架构 企业内架构 高性能计算用于高级分析 大数据分析和机器学习的商业和企业用例 构建世界一流的大数据分析解决方案
为了进一步讨论,我们将在本章中澄清以下概念:
-
大数据的定义
-
如果数据一直存在,为什么我们现在谈论大数据?
-
大数据的简史
-
大数据的类型
-
您应该从哪里开始寻找大数据解决方案?
什么是大数据?
术语“大”是相对的,通常在不同情况下可以具有不同的意义,无论是在数量还是应用方面。大数据的一个简单,尽管天真的定义是大量信息的集合,无论是存储在个人笔记本电脑上的数据还是存储在大型企业服务器上的数据,使用现有或传统工具进行分析都是非平凡的。
今天,行业通常将以太字节或拍字节及更大规模的数据视为大数据。在本章中,我们将讨论大数据范式的出现及其广泛特征。随后,我们将详细探讨不同领域。
数据的简史
计算的历史是一个迷人的故事,从查尔斯·巴贝奇在 19 世纪 30 年代中期发明的分析引擎到现代超级计算机,计算技术引领了全球变革。由于空间限制,不可能涵盖所有领域,但提供了有关数据和数据存储的高层介绍,以提供历史背景。
信息时代的黎明
大数据一直存在。美国国会图书馆是世界上最大的图书馆,收藏了 1.64 亿件物品,包括 2,400 万本书和 1.25 亿件非分类收藏品。[来源:www.loc.gov/about/general-information/
]。
机械数据存储可以说最早始于由赫尔曼·霍勒里斯于 1880 年发明的穿孔卡。这些穿孔卡基本上是基于巴西尔·布什翁的先前工作,他在 1725 年发明了用于控制织机的穿孔带,霍勒里斯的穿孔卡提供了一个接口,用于进行制表和甚至打印聚合物。
IBM 开创了穿孔卡的工业化,并很快成为存储信息的事实选择。
艾伦·图灵博士和现代计算
穿孔卡建立了强大的存在,但仍然缺少一个元素——这些机器,尽管设计复杂,但不能被认为是计算设备。一个正式的通用机器,足够多样化地解决各种问题,尚未被发明。
1936 年,图灵从剑桥大学毕业后,发表了一篇开创性的论文,题为《论可计算数及对决策问题的应用》,在这篇论文中,他在库尔特·哥德尔的不完备定理基础上,形式化了我们今天的数字计算概念。
存储程序计算机的出现
存储程序计算机的第一个实现是曼彻斯特小型实验机(SSEM),该设备可以在内存中保存程序,于 1948 年在曼彻斯特大学开发[来源:en.wikipedia.org/wiki/Manchester_Small-Scale_Experimental_Machine
]。这引入了 RAM,随机存取存储器(或更一般地说,内存)的概念,这是今天计算机中的内存。在 SSEM 之前,计算机具有固定存储;也就是说,所有功能都必须预先布线到系统中。能够在 RAM 等临时存储设备中动态存储数据的能力意味着机器不再受存储设备容量的限制,而是可以容纳任意数量的信息。
从磁性设备到固态硬盘
20 世纪 50 年代初,IBM 推出了磁带,基本上使用金属磁带上的磁化来存储数据。随后,于 1956 年快速相继推出了硬盘驱动器,它们使用磁盘盘片而不是磁带来存储数据。
最早的硬盘模型容量不到 4MB,占据了大约两个中等大小的冰箱的空间,成本超过 36,000 美元——与今天的硬盘相比贵了 3 亿倍。磁化表面很快成为二次存储的标准,迄今为止,它们的变体已经在各种可移动设备上实现,例如 90 年代末的软盘、CD 和 DVD。
固态硬盘(SSD),硬盘的继任者,最早由 IBM 于 20 世纪 50 年代中期发明。与硬盘相比,SSD 磁盘使用非易失性存储器存储数据,该存储器使用带电硅基底存储数据。由于没有机械运动部件,检索存储在 SSD 中的数据的时间(寻道时间)相对于硬盘等设备快了一个数量级。
如果数据一直存在,为什么我们现在谈论大数据
到了 21 世纪初,计算和存储等技术的快速进步使用户能够以前所未有的效率收集和存储数据。互联网进一步推动了这一进程,提供了一个具有全球规模无限交换信息能力的平台。技术以惊人的速度发展,并引发了由社交媒体、智能手机等连接设备以及宽带连接和用户参与等工具推动的主要范式转变,甚至在世界偏远地区也是如此。
总的来说,这些数据的大部分是由基于网络的来源生成的,例如 Facebook 等社交网络和 YouTube 等视频分享网站。在大数据术语中,这也被称为非结构化数据;也就是说,不是固定格式的数据,例如电子表格中的数据,也不是可以轻松存储在传统数据库系统中的数据。
计算能力的同时进步意味着尽管数据生成的速率非常高,但仍然可以在计算上进行分析。机器学习算法曾经被认为由于数据量和算法复杂性而难以处理,现在可以使用各种新的范例,如集群或多节点处理,以一种比以前需要专用机器更简单的方式进行分析。
每分钟生成的数据图表。来源:DOMO Inc.
大数据的定义
总体而言,生成的数据量被称为大数据,包括从基本数据挖掘到高级机器学习等各种能力的分析被称为大数据分析。由于量化什么样的数据足够大以满足将任何特定用例分类为大数据分析的标准是相对的,因此并没有确切的定义。相反,在一般意义上,对大规模数据集进行分析,例如十几或数百吉字节到皮字节的数据,可以被称为大数据分析。这可以是简单的查找大型数据集中的行数,也可以是对其应用机器学习算法。
大数据分析的构建模块
从根本上说,大数据系统可以被认为有四个主要层,每一层都是不可或缺的。在各种教科书和文献中都有许多这样的层,因此可能存在歧义。尽管如此,在高层次上,这里定义的层是直观和简单的:
大数据分析层
各个层次如下所示:
-
硬件:提供计算骨干、存储数据的服务器以及跨不同服务器组件的网络连接的设备是定义硬件堆栈的一些元素。实质上,提供计算和存储能力的系统以及支持这些设备互操作性的系统形成了构建模块的基础层。
-
软件:在硬件层托管的数据集上进行分析的软件资源,如 Hadoop 和 NoSQL 系统,代表了大数据堆栈中的下一个层次。分析软件可以分为各种子类。用于促进的两个主要高级分类的分析软件工具是:
-
数据挖掘:提供对大型数据集进行聚合、数据集之间的连接和数据透视表的软件属于这一类别。标准的 NoSQL 平台,如 Cassandra、Redis 等,是大数据分析的高级数据挖掘工具。
-
统计分析:提供超出简单数据挖掘的分析能力的平台,例如运行从简单回归到高级神经网络的算法,如 Google TensorFlow 或 R,属于这一类别。
-
数据管理:数据加密、治理、访问、合规性等功能对于任何企业和生产环境来说都是非常重要的,以管理和在某种程度上减少操作复杂性形成了下一个基本层。虽然它们不如硬件或软件那么具体,但数据管理工具提供了一个明确定义的框架,组织可以在其中履行其安全和合规性等义务。
-
最终用户:分析软件的最终用户构成了大数据分析的最终方面。毕竟,数据平台的价值取决于它能够被有效利用的程度,并且能够解决特定于业务的用例。这就是实践者的角色,他们利用分析平台来获取价值。术语“数据科学家”通常用来表示实施基础大数据分析能力的个人,而业务用户则获得了比传统系统中更快的访问和分析能力。
大数据类型
数据可以被广泛分类为结构化、非结构化或半结构化。尽管这些区别一直存在,但随着大数据的出现,将数据分类到这些类别中变得更加突出。
结构化
结构化数据,顾名思义,表示具有定义的组织结构的数据集,例如 Microsoft Excel 或 CSV 文件。在纯数据库术语中,数据应该可以使用模式来表示。例如,以下表格代表了联合国在其 2017 年世界幸福指数排名中发布的世界上前五个最幸福国家的典型表示。
我们可以清楚地定义列的数据类型——排名、得分、人均国内生产总值、社会支持、健康预期寿命、信任、慷慨和乌托邦都是数值列,而国家则使用字母,或更具体地说是字符串。
有关更多清晰的信息,请参考以下表格:
排名 | 国家 | 得分 | 人均国内生产总值 | 社会支持 | 健康预期寿命 | 慷慨 | 信任 | 乌托邦 |
---|---|---|---|---|---|---|---|---|
1 | 挪威 | 7.537 | 1.616 | 1.534 | 0.797 | 0.362 | 0.316 | 2.277 |
2 | 丹麦 | 7.522 | 1.482 | 1.551 | 0.793 | 0.355 | 0.401 | 2.314 |
3 | 冰岛 | 7.504 | 1.481 | 1.611 | 0.834 | 0.476 | 0.154 | 2.323 |
4 | 瑞士 | 7.494 | 1.565 | 1.517 | 0.858 | 0.291 | 0.367 | 2.277 |
5 | 芬兰 | 7.469 | 1.444 | 1.54 | 0.809 | 0.245 | 0.383 | 2.43 |
2017 年世界幸福报告[来源:en.wikipedia.org/wiki/World_Happiness_Report#cite_note-4
]
商业数据库,如 Teradata、Greenplum 以及开源领域中的 Redis、Cassandra 和 Hive,都是提供管理和查询结构化数据能力的技术的例子。
非结构化
非结构化数据包括任何没有预定义组织结构的数据集,就像前一节中的表格一样。口头语言、音乐、视频,甚至书籍,包括这本书,都被认为是非结构化。这绝不意味着内容没有组织。事实上,一本书有目录、章节、子章节和索引——在这个意义上,它遵循着明确的组织。
然而,将每个单词和句子表示为严格的一组规则是徒劳的。一个句子可以由单词、数字、标点符号等组成,并且不像电子表格那样具有预定义的数据类型。要结构化,这本书需要在每个句子中具有一组确切的特征,这既不合理也不切实际。
来自社交媒体的数据,例如 Twitter 上的帖子、Facebook 上朋友的消息和 Instagram 上的照片,都是非结构化数据的例子。
非结构化数据可以以各种格式存储。它们可以是二进制大对象,或者在文本数据的情况下,是保存在数据存储介质中的自由文本。对于文本数据,通常使用 Lucene/Solr、Elasticsearch 等技术进行查询、索引和其他操作。
半结构化
半结构化数据是指既具有组织架构元素又具有任意方面的数据。个人电话日记(如今越来越少见!)包括姓名、地址、电话号码和备注的列,可以被视为半结构化数据集。用户可能不知道所有个人的地址,因此一些条目可能只有电话号码,反之亦然。
同样,备注栏可能包含额外的描述性信息(如传真号码、与个人相关的亲属姓名等)。这是一个任意的字段,允许用户添加补充信息。因此,姓名、地址和电话号码的列可以被视为结构化的,因为它们可以以表格格式呈现,而备注部分在这种意义上是非结构化的,因为它可能包含一组无法在日记的其他列中表示的描述性信息。
在计算中,半结构化数据通常由可以封装结构化和无模式或任意关联的格式(如 JSON)表示,通常使用键值对。更常见的例子可能是电子邮件,它既有一个结构化部分,如发件人姓名、接收邮件的时间等,这对所有电子邮件都是共同的,也有一个由电子邮件的正文或内容表示的非结构化部分。
像 Mongo 和 CouchDB 这样的平台通常用于存储和查询半结构化数据集。
大数据的来源
今天的技术使我们能以惊人的速度收集数据–无论是在数量还是种类上。有各种各样的数据来源,但在大数据的背景下,主要的来源如下:
-
社交网络:可以说,我们今天所知的所有大数据的主要来源是过去 5-10 年里蓬勃发展的社交网络。这基本上是由数百万社交媒体帖子和通过用户在全球范围内的网络互动每秒生成的其他数据所代表的非结构化数据。全球范围内对互联网的访问增加已经成为社交网络数据增长的自我实现行为。
-
媒体:在很大程度上是社交网络增长的结果,媒体代表了每天发生的数百万甚至数十亿的音频和视觉上传。在 YouTube 上传的视频、在 SoundCloud 上的音乐录音以及在 Instagram 上发布的图片是媒体的主要例子,其数量继续以不受限制的方式增长。
-
数据仓库:公司长期以来一直在投资于专门的数据存储设施,通常被称为数据仓库。数据仓库本质上是公司希望维护和目录化以便轻松检索的历史数据的集合,无论是用于内部使用还是监管目的。随着行业逐渐转向将数据存储在 Hadoop 和 NoSQL 等平台上的做法,越来越多的公司正在将数据从现有的数据仓库转移到一些新技术上。公司的电子邮件、会计记录、数据库和内部文件是一些现在正在转移到 Hadoop 或类似 Hadoop 平台的半结构化数据的例子。
-
传感器:大数据领域最近的一个现象是从传感器设备收集数据。虽然传感器一直存在,像石油和天然气等行业几十年来一直在使用钻井传感器测量油井的数据,但可穿戴设备的出现,也被称为物联网,如 Fitbit 和 Apple Watch,意味着现在每个人都可以以与十年前几个油井相同的速度传输数据。
可穿戴设备可以在任何时候从个人身上收集数百个测量数据。虽然还不是一个大数据问题,但随着行业的不断发展,传感器相关的数据很可能会变得更类似于通过社交网络活动在网络上生成的那种即时数据。
大数据的 4V
在大数据的背景下,4V 的话题已经被过度使用,开始失去了一些最初的魅力。尽管如此,为了了解这些 V 代表的背景情况,它有助于记住这些 V 的意义,以便进行对话。
总的来说,4V 表示以下内容:
-
体积:正在生成的数据量
-
多样性:不同类型的数据,如文本、媒体和传感器或流数据
-
速度:数据生成的速度,比如在任何时候通过社交网络交换的数百万条消息
-
真实性:这是对 3V 中的一个较新的补充,表示数据中固有的噪音,比如记录信息中的不一致之处,需要额外的验证
你如何知道你有一个大数据问题,以及你从哪里开始寻找大数据解决方案?
最后,大数据分析是指将数据投入实际运作的实践–换句话说,通过使用适当的技术从大量数据中提取有用信息的过程。对于许多用于表示不同类型分析的术语,没有确切的定义,因为它们可以以不同的方式解释,因此意义可能是主观的。
尽管如此,这里提供了一些作为参考或起点的术语,以帮助您形成初步印象:
-
数据挖掘:数据挖掘是指通过运行查询或基本汇总方法(如聚合)从数据集中提取信息的过程。从包含一百万个产品的所有销售记录的数据集中找出销售量前十的产品,就是挖掘的过程:也就是从数据集中提取有用信息。Cassandra、Redis 和 MongoDB 等 NoSQL 数据库是具有强大数据挖掘能力的典型工具。
-
商业智能:商业智能是指诸如 Tableau、Spotfire、QlikView 等工具,提供前端仪表板,使用户能够使用图形界面查询数据。随着用户寻求提取信息,仪表板产品在数据增长的同时也变得更加突出。易于使用的界面,具有查询和可视化功能,可以被技术和非技术用户普遍使用,为数据分析的民主化访问奠定了基础。
-
可视化:数据可以通过易于理解的可视化结果简洁直观地表达。可视化在更深入的分析之前,在理解数据的性质和分布方面发挥了关键作用。JavaScript 的发展,如 D3.js 和百度的 ECharts,在长期的沉寂后又出现了,是开源领域可视化包的典型例子。大多数商业智能工具都包含先进的可视化功能,因此它已经成为任何成功分析产品的不可或缺的资产。
-
统计分析:统计分析是指允许最终用户在数据集上运行统计操作的工具或平台。这些工具传统上已经存在了很多年,但随着大数据的出现以及大量数据在进行高效统计操作方面所带来的挑战,它们已经开始受到关注。R 语言和 SAS 等产品是计算统计领域常见的工具。
-
机器学习:机器学习,通常被称为预测分析、预测建模等各种名称,实质上是应用超越传统统计领域的先进算法的过程。这些算法不可避免地涉及数百甚至数千次迭代。这些算法不仅本质上复杂,而且计算密集。
技术的进步是机器学习在分析中增长的关键驱动因素,以至于它现在已经成为行业中常用的术语。自动驾驶汽车、根据交通模式调整地图上的交通数据以及 Siri 和 Cortana 等数字助手的创新是机器学习在实际产品中的商业化的例子。
摘要
大数据无疑是一个庞大的主题,乍一看似乎过于复杂。熟能生巧,对大数据的研究也是如此——你越是参与其中,就越熟悉其中的话题和术语,对这个主题也就越感到舒适。
对大数据分析主题的各个方面进行深入研究将帮助您对这一主题形成直观的感觉。本书旨在全面概述这一主题,并将涵盖广泛的领域,如 Hadoop、Spark、NoSQL 数据库以及基于硬件设计和云基础设施的主题。在下一章中,我们将介绍大数据挖掘的概念,并讨论大数据技术的技术要素以及选择标准。
第二章:大规模数据挖掘
在企业环境中实施一个满足特定业务需求的大数据挖掘平台并不是一件简单的事情。虽然构建一个大数据平台相对简单,但是这些工具的新颖性在于对传统数据挖掘方法习惯的面向业务的用户的采用方面提出了挑战。这最终是衡量平台在组织内部变得多成功的一个标准。
本章介绍了与大数据分析相关的一些显着特征,适用于分析工具的从业者和最终用户。这将包括以下主题:
-
什么是大数据挖掘?
-
企业中的大数据挖掘:
-
构建用例
-
解决方案的利益相关者
-
实施生命周期
-
大数据挖掘的关键技术:
-
选择硬件堆栈:
-
单/多节点架构
-
基于云的环境
-
选择软件堆栈:
-
Hadoop、Spark 和 NoSQL
-
基于云的环境
什么是大数据挖掘?
大数据挖掘是大数据分析的两个广泛类别中的第一个,另一个是预测分析,我们将在后面的章节中介绍。简单来说,大数据挖掘指的是处理大规模数据集的整个生命周期,从采购到实施相应工具进行分析。
接下来的几章将阐述在组织中进行的任何大数据项目的一些高层特征。
企业中的大数据挖掘
在中大型企业中实施大数据解决方案可能是一项具有挑战性的任务,因为考虑因素的范围极其动态和多样化,其中之一是确定解决方案将解决哪些具体的业务目标。
为大数据战略建立案例
大数据挖掘最重要的方面也许是确定平台将解决的适当用例和需求。任何大数据平台的成功很大程度上取决于在业务单位中找到相关问题,这些问题将为部门或组织提供可衡量的价值。用于收集大量传感器或流数据的解决方案的硬件和软件堆栈将与用于分析大量内部数据的解决方案有实质性的不同。
以下是一些建议的步骤,根据我的经验,这些步骤在构建和实施企业大数据战略方面被发现特别有效:
- 谁需要大数据挖掘:确定哪些业务团队将最显著地受益于大数据挖掘解决方案是这个过程的第一步。这通常涉及已经使用大型数据集、对业务至关重要,并且对日常工作流程的数据访问或信息分析时间进行优化将产生直接收入影响的团队。
例如,在制药组织中,这可能包括商业研究、流行病学、卫生经济学和结果。在金融服务组织中,这可能包括算法交易台、定量研究,甚至后勤部门。
- 确定用例:在前一步骤中确定的部门可能已经有一个能够满足团队需求的平台。在多个用例和部门(或它们的集合)之间进行优先排序需要对各自业务团队的工作有个人熟悉度。
大多数组织遵循分层结构,业务同事之间的互动可能主要沿着等级线进行。确定有影响力的分析用例需要在从业者和利益相关者之间进行密切合作;即对部门进行监督的管理层以及进行实际分析的员工。业务利益相关者可以阐明他或她的业务的哪些方面将从更高效的数据挖掘和分析环境中获益最大。从业者提供有关操作层面存在的挑战的见解。巩固操作和管理方面的渐进改进,以确定最佳结果,必然会带来更快和更好的结果。
-
利益相关者的支持:在着手处理用例之前,应确立利益相关者的支持,换句话说,应在决策者和能够独立做出预算决策的人员之间形成共识。一般来说,应该获得多方支持,以确保有一组主要和次要来源,可以为任何早期成功的扩展提供适当的支持和资金。支持过程不必是确定性的,在大多数情况下可能不可能。相反,对某个特定用例将带来的价值达成一般共识有助于建立一个基准,可以在成功执行用例的基础上加以利用。
-
早期成功和投入-回报比:一旦确定了适当的用例,找到具有最佳投入-回报比的用例至关重要。在较小的预算内,可以在较短时间内实施的相对较小的用例,以优化特定的业务关键功能,有助于展示早期成功,从而增加了所讨论的大数据解决方案的可信度。我们无法精确量化这些无形属性,但我们可以假设:
在这种情况下,“投入”是实施用例所需的时间和工作。这包括诸如采购与解决方案相关的硬件和/或软件需要多长时间,实施解决方案需要多少资源或等效的“人时”,以及整体运营开销等方面。相对于实施可能需要组织进行漫长采购和风险分析的商业解决方案,开源工具可能具有较低的准入门槛。同样,跨部门跨项目需要多个资源的时间的项目可能比只需单个部门员工执行的项目持续时间更长。如果净投入足够低,也可以并行运行多个练习,只要不影响项目的质量。
- 利用早期成功:在早期成功阶段成功实施一个或多个项目通常为发展大数据分析平台的更大战略奠定了基础,这超出了单个部门的需求,并具有更广泛的组织级影响。因此,早期成功作为建立大数据价值的第一步,但至关重要,以展示给可能对其可行性和相关性持怀疑态度的观众。
实施生命周期
正如前文所述,实施过程可能涉及多个步骤。这些步骤通常是迭代的,需要采用试错方法。这将需要相当多的毅力和坚持,因为大多数工作将以不同程度的成功和失败为特征。
在实践中,大数据战略将包括多个利益相关者,合作方法通常会产生最佳结果。业务赞助商、业务支持和 IT & 分析是三个广泛的利益相关者类别,共同创建一个适当的统一解决方案,满足业务需求,同时受到预算和 IT 能力的限制。
解决方案的利益相关者
大数据解决方案的利益相关者的确切性质是主观的,并且会根据使用案例和问题领域而变化。一般来说,以下可以被认为是这方面的高级代表:
-
业务赞助商:为项目提供支持和/或资金的个人或部门。在大多数情况下,这个实体也将成为解决方案的受益者。
-
实施组:从实际操作的角度实施解决方案的团队。这通常是大多数公司的 IT 或分析部门,负责平台的设计和部署。
-
IT 采购:大多数组织的采购部门负责审查解决方案,以评估其竞争定价和组织视角下的可行性。遵守内部 IT 政策和评估其他方面,如许可成本等,是采购提供的一些服务,特别是对于商业产品。
-
法律:所有产品,除非是内部开发的,都一定会有关联的使用条款和条件。开源产品可能具有一系列属性,定义了使用的可允许性和限制性。相对于 GNU GPL(通用公共许可证),开源软件许可证,如 Apache 2.0、MIT 和 BSD,通常更具有可允许性。对于商业解决方案,这个过程更加复杂,因为它需要分析供应商特定的协议,并且根据许可条款和条件的性质,可能需要很长时间来评估和获得批准。
实施解决方案
解决方案的最终实施是实施组、业务受益者和辅助部门之间合作的结果。从开始到结束进行项目的时间可能会因项目规模而异,对于大多数小型项目来说,可能需要 3-6 个月,正如在早期成果部分所解释的那样。更大的努力可能需要几个月到几年的时间来完成,并且在实施和部署期间,会采用敏捷的产品管理框架逐步增加能力。
以下截图让我们对概念有了很好的理解:
显示工作流程的高级图像
这些图像和图标来自:
-
图标由 Freepik 制作(
www.freepik.com
)来自 www.flaticon.com,由 CC 3.0 BY 许可 -
图标由 Vectors Market 制作(
www.flaticon.com/authors/vectors-market
)来自www.flaticon.com,由 CC 3.0 BY 许可 -
图标由 Prosymbols 制作(
www.flaticon.com/authors/prosymbols
)来自www.flaticon.com,由 CC 3.0 BY 许可 -
Vectors 由 Vecteezy 制作(
www.vecteezy.com
)
大数据平台的技术要素
到目前为止,我们的讨论集中在企业环境中设计和部署大数据解决方案的高级特征上。现在我们将把注意力转向这些工作的技术方面。我们将不时地在讨论的主题中加入高层次的信息,除了技术方面的基础知识。
在技术层面上,主要有两个考虑因素:
-
硬件堆栈的选择
-
软件和BI(商业智能)平台的选择
在过去的 2-3 年中,公司将其流程转移到基于云的环境作为内部基础设施的补充解决方案变得越来越普遍。因此,基于云的部署变得非常普遍,因此,增加了一个关于内部部署与基于云的额外部分。请注意,术语On-premises可以与In-house、On-site和其他类似的术语互换使用。
你经常会听到On-premise这个术语被用作On-premises的替代。正确的术语是On-premises。Chambers 词典将premise定义为*premise 名词 1(也称为 premises)假定为真的东西,作为陈述更进一步的基础。*另一方面,premises是用来表示建筑物(等等)的术语,这可能更有意义。
硬件堆栈的选择
硬件的选择通常取决于所选择的解决方案类型以及硬件的位置。正确的选择取决于诸多关键指标,如数据类型(结构化、非结构化或半结构化)、数据大小(千兆字节、千兆字节、百万兆字节)以及在一定程度上数据更新的频率。最佳选择需要对这些变量进行正式评估,这将在本书的后面讨论。在高层次上,我们可以总结出三种硬件架构模型:
-
多节点架构:这通常涉及多个相互连接的节点(或服务器),并且遵循多节点或分布式计算的原则。多节点架构的一个典型例子是 Hadoop,其中多个服务器维护双向通信以协调作业。其他技术,如 Cassandra 这样的 NoSQL 数据库和 Elasticsearch 这样的搜索和分析平台,也是基于多节点计算架构原则运行的。它们大多利用商品服务器,这是企业标准下相对低端机器的另一个名称,它们协同工作以提供大规模数据挖掘和分析能力。多节点架构适用于托管在千兆字节及以上范围内的数据。
-
单节点架构:单节点是指在单个服务器上进行计算。随着多节点计算工具的出现,这种情况相对较少,但仍然比分布式计算架构具有巨大优势。分布式计算的谬论概述了一组关于分布式系统实现的断言或假设,如网络的可靠性、延迟成本、带宽和其他考虑因素。
如果数据集是结构化的,主要包含文本数据,并且在 1-5 TB 的范围内,在当今的计算环境中,完全有可能使用特定技术在单节点机器上托管这样的数据集,就像后面的章节中所展示的那样。
- 基于云的架构:在过去几年中,行业中出现了许多基于云的解决方案。这些解决方案通过提供一个平台,极大地降低了大数据分析的准入门槛,使得根据手头任务的需求轻松提供硬件资源成为可能。这在采购、管理和维护物理硬件以及在内部数据中心设施中托管它们方面大大减少了重大的开销。
云平台,如亚马逊网络服务、微软的 Azure 和谷歌计算环境,允许企业按小时每个实例低至 1 美分的成本提供 10 到 1000 个节点。
随着云供应商对传统的实体托管设施的日益主导地位,出现了几种用于管理客户云环境的互补服务。
例如,云管理公司,如提供大数据服务解决方案的 Altiscale 和促进选择和管理多个基于云的解决方案的 IBM Cloud Brokerage。
硬件成本的指数级下降:过去几年,硬件成本呈指数级下降。以 Statistic Brain 的研究为例,2013 年硬盘存储的成本约为每 GB 4 美分。与 2000 年的每 GB 7 美元以及 80 年代初期每 GB 超过 10 万美元相比。考虑到商业软件的高昂许可成本,这往往超过了硬件成本,因此有必要分配足够的预算来采购能力强大的硬件解决方案。软件需要适当的硬件才能提供最佳性能,对硬件选择的重视程度与选择适当的软件一样重要。
软件堆栈的选择
数据挖掘软件堆栈的选择因个人情况而异。特定于数据挖掘的最流行的选项以及一些不那么知名但同样能够处理大规模数据集的替代方案都显示在下面:
-
Hadoop 生态系统:大数据术语可以说是随着 Hadoop 的出现在流行领域中得到了发展。Hadoop 生态系统包括在 Apache 软件基金会的支持下运行的多个项目。Hadoop 支持几乎所有大数据领域中已知的各种类型的数据集,如结构化、非结构化和半结构化。其繁荣的辅助工具生态系统增加了新功能,以及一个快速发展的市场,公司们正在竞相展示大数据领域的下一个大事件,这意味着 Hadoop 将在可预见的未来仍然存在。除了大型生态系统中存在的项目外,Hadoop 有四个主要组件。它们如下:
-
Hadoop Common:支持其他 Hadoop 模块的通用实用程序
-
Hadoop 分布式文件系统(HDFS™):提供对应用程序数据的高吞吐量访问的分布式文件系统。
-
Hadoop YARN:用于作业调度和集群资源管理的框架
-
Hadoop MapReduce:基于 YARN 的用于大型数据集的并行处理系统
-
Apache Spark™:Apache Spark 最初是在加州大学伯克利分校的 AMPLab 首次构想的一个多节点计算框架项目,作为一个提供无缝接口来运行并行计算并克服 Hadoop MapReduce 框架局限性的平台。特别是,Spark 内部利用了一种称为DAG(有向无环图)的概念,该概念将一组操作优化为更小或更高效的一组操作。此外,Spark 公开了几个API(应用程序编程接口),用于常用语言,如 Python(PySpark)和 Scala(本地可用接口)。这消除了进入 Hadoop 领域的一个障碍,即需要掌握 Java 的知识。
最后,Spark 引入了一种称为弹性分布式数据集(RDD)的数据结构,它提供了一种将数据存储在内存中的机制,从而显着提高了数据检索和随后处理的时间:
-
- 集群管理器:构成 Spark 集群的节点使用集群管理器进行通信,集群管理器管理集群中的节点之间的整体协调。截至目前,集群管理器可以是独立的 Spark 集群管理器、Apache Mesos 或 YARN。还有一个额外的功能,即使用 spark-ec2 在 AWS EC2 实例上运行 Spark,它会自动设置一个运行 Spark 程序的环境。
-
- 分布式 存储:Spark 可以从各种基础分布式存储系统中访问数据,如 HDFS、S3(AWS 存储)、Cassandra、HBase、Hive、Tachyon 和任何 Hadoop 数据源。需要注意的是,Spark 可以作为独立产品使用,不需要 Hadoop 进行操作。对于 Spark 的新手,他们常常误以为 Spark 操作需要 Hadoop,或者更具体地说需要 HDFS 文件系统。这是不正确的。Spark 可以支持多种类型的集群管理器以及后端存储系统,如本节所示。
-
NoSQL 和传统数据库:在选择软件堆栈方面的第三个考虑是 NoSQL 数据库。最近出现的 NoSQL 一词旨在区分不遵循传统关系数据库模型的数据库。有开源和商业版本的 NoSQL 数据库,甚至有越来越常见的基于云的选项。NoSQL 数据库有各种广泛的分类,一些更常见的范式如下:
-
键值:这些 NoSQL 数据库根据哈希的原则存储数据——一个唯一的键标识了与该键相关的一组属性。在这种术语中,一个键的例子可能是个人的国民身份证号码(如美国的社会安全号码或印度的 Aadhaar)。这可以与个人的姓名、地址、电话号码和其他变量相关联。数据库的最终用户可以通过 ID 号码查询,直接访问有关个人的信息。像 Redis 这样的开源键值数据库和像 Riak 这样的商业数据库非常受欢迎。
-
内存中:虽然数据库一直在使用内存设施,比如将缓存存储在内存中以提供比存储在磁盘上更快的访问,但随着大数据的出现,它们被更广泛地采用。在内存中访问数据的速度比从磁盘访问相同的信息快几个数量级(约 100 纳秒),后者的速度是前者的 100,000 倍(1-10 毫秒)。一些 NoSQL 数据库,如 Redis 和 KDB+,利用临时内存存储以提供对经常使用的数据更快的访问。
-
列式:这些数据库将多列数据附加到表中,而不是行。列式存储相对于基于行的存储的主要优势在于,列式布局提供了更快地访问数据的手段,减少了 I/O 开销,特别适用于分析用例。通过将数据分隔成单独的列,数据库查询可以通过扫描适当的列而不是逐行扫描表来检索数据,并且可以非常好地利用并行处理设施。知名的列式数据库包括 Cassandra、Google BigTable 等。
-
面向文档:在许多方面,文档导向数据库被认为是纯键值存储的一种升级,它存储不符合任何特定模式的数据,比如新闻文章等非结构化文本。这些数据库提供了一种方式来封装多个键值对中的信息,这些键值对在结构上不一定要在所有其他条目中保持一致。因此,像 MongoDB 这样的文档数据库被广泛用于媒体相关组织,如纽约时报和福布斯,以及其他主流公司。
-
基于云的解决方案: 最后,诸如 AWS Redshift、Azure SQL 数据仓库和 Google Bigquery 等大规模数据挖掘的基于云的解决方案允许用户直接在云供应商的平台上查询数据集,而无需创建自己的架构。尽管最终用户可以选择拥有自己的内部专家,如 Redshift 系统管理员,但基础设施、维护和日常例行任务的管理大部分由供应商执行,从而减少了客户端的运营开销。
摘要
在本章中,我们对大数据和企业中实施大数据解决方案的一些组成部分进行了高层次的概述。大数据需要选择最佳的软件和硬件堆栈,这是一项非常不容易的工作,其中一个原因是行业中有数百种解决方案。尽管大数据战略的话题可能被视为更适合管理层而不是技术观众,但理解其中的细微差别是至关重要的。
请注意,如果没有适当的、明确定义的策略和相应的高层支持,IT 部门将在提供成功解决方案的程度上受到限制。此外,解决方案,包括硬件软件堆栈,应该能够得到现有 IT 资源的充分管理和支持。大多数公司会发现,对于大数据实施来说,招聘新员工是必不可少的。由于这类实施需要评估各种因素 - 业务需求、预算、资源和其他变量,因此根据规模和范围,通常需要几个月甚至一年以上的前期时间。
这些主题将在后面的章节中深入讨论,本节作为对该主题的初步介绍。
第三章:分析工具包
今天有几个平台用于大规模数据分析。在广义上,这些平台分为主要用于数据挖掘的平台,比如使用 NoSQL 平台分析大型数据集,以及用于数据科学的平台,即机器学习和预测分析。通常,解决方案可能具有这两种特征——一个用于存储和管理数据的强大基础平台,以及在其之上构建的提供数据科学附加功能的解决方案。
在本章中,我们将向您展示如何安装和配置您的分析工具包,这是我们在接下来的章节中将使用的一系列软件:
-
分析工具包的组件
-
系统建议
-
在笔记本电脑或工作站上安装
-
在云上安装
-
安装 Hadoop
-
Hadoop 分布
-
Cloudera Hadoop 分布(CDH)
-
安装 Spark
-
安装 R 和 Python
分析工具包的组件
本书将利用几种用于大数据挖掘和更一般的数据科学的关键技术。我们的分析工具包包括 Hadoop 和 Spark,它们可以在用户的本地机器上安装,也可以在云上安装;还有 R 和 Python,它们都可以在用户的机器上安装,也可以在云平台上安装。您的分析工具包将包括:
软件/平台 | 用于数据挖掘 | 用于机器学习 |
---|---|---|
Hadoop | X | |
Spark | X | X |
Redis | X | |
MongoDB | X | |
开源 R | X | X |
Python(Anaconda) | X | X |
Vowpal Wabbit | X | |
LIBSVM,LIBLINEAR | X | |
H2O | X |
系统建议
如果您在本地机器上安装 Hadoop,建议您的系统至少具有 4-8GB 的 RAM(内存)和至少 50GB 的充足的磁盘空间。理想情况下,8GB 或更多内存对于大多数应用程序来说足够了。低于这个数值,性能会降低,但不会阻止用户进行练习。请注意,这些数字是适用于本书中概述的练习的估计值。生产环境自然会有更高的要求,这将在后面讨论。
安装分析软件,特别是像 Hadoop 这样的平台,可能在技术复杂性方面非常具有挑战性,用户很常见地会遇到必须要费力解决的错误。用户花费更多时间尝试解决错误和修复安装问题,而不是他们理想情况下应该花费的时间。这种额外的开销可以通过使用虚拟机(VMs)或者最近更常用的 Docker 等容器来轻松减轻。对于像 R 和 Python 这样更简单的平台,我们将使用预装有各种库的开源版本。
在笔记本电脑或工作站上安装
本书中的练习可以在任何 Windows、macOS 或 Linux 机器上进行。用户需要 Oracle VirtualBox(可以从www.virtualbox.org/wiki/Downloads
)开始安装分析工具包所需的软件。
在云上安装
在您的物理硬件上安装软件的另一种选择是使用基于云的服务。云服务,比如亚马逊的 AWS(亚马逊网络服务)和微软的 Azure,提供了一个极其灵活和多功能的环境,可以按需提供服务器,每小时的使用成本只需几美分到几美元。虽然云安装超出了本书的范围,但非常简单地创建一个免费的 AWS 账户,并使用它来安装本书中讨论的不同分析软件的各个部分。请注意,如果您使用 AWS/Azure 或任何其他云服务,您将需要使用 Cloudera Hadoop 分布的 Docker 版本。
安装 Hadoop
安装 Hadoop 有几种方法。最常见的方法有:
-
从
hadoop.apache.org
的源文件中安装 Hadoop -
使用来自 Cloudera 和 Hortonworks 等商业供应商的开源发行版进行安装
在这个练习中,我们将安装Cloudera 分布式 Apache Hadoop(CDH),这是一个由几个 Hadoop 和与 Apache 相关的产品组成的集成平台。Cloudera 是一个流行的商业 Hadoop 供应商,除了其自己的 Hadoop 版本外,还为企业规模的 Hadoop 部署提供托管服务。在我们的情况下,我们将在 VM 环境中安装 HDP Sandbox。
安装 Oracle VirtualBox
VM 环境本质上是现有操作系统的副本,可能已经预装了软件。VM 可以以单个文件的形式交付,这允许用户通过仅启动文件而不是重新安装操作系统并配置它来模拟另一个系统来复制整个机器。VM 在一个独立的环境中运行;也就是说,它不依赖于主机操作系统来提供其功能。
要安装 CDH Quickstart VM,我们将使用 Oracle VirtualBox,该软件用于从 VM 文件启动 VMs。
在 VirtualBox 中安装 CDH 的步骤:
-
从
www.virtualbox.org/wiki/Downloads
下载适合您系统的 Oracle VirtualBox(Windows、macOS 或 Linux)(如果无法访问此链接,请转到www.virtualbox.org/
并选择适当的链接转到下载页面)。 -
双击 Oracle VirtualBox 可执行文件,并按照屏幕上的提示进行安装(您可以接受屏幕上显示的默认设置)。
-
安装了 VirtualBox 后,您还应该安装可在
www.oracle.com/technetwork/server-storage/virtualbox/downloads/index.html#extpack
下载的Oracle VM VirtualBox 扩展包。
下载与您的环境相关的扩展包文件,并单击/双击该文件。这将在 Oracle VM VirtualBox 应用程序中打开并在 VirtualBox 环境中安装扩展包。
下载和安装 CDH Quickstart VM:可以从 Cloudera 网站下载 CDH 的 Quickstart VM 或 Docker 镜像。步骤如下:
- 转到
www.cloudera.com
,然后单击页面顶部的下载菜单中的 Quickstart VMs。如果导航已更改,可以在 Google 上搜索 Cloudera Quickstart VM,通常会直接带您到 Cloudera 下载页面:
Cloudera 主页上的 QuickStart VM 链接
- 这将打开 CDH 下载页面的 Quickstart。在“选择平台”菜单中,选择VirtualBox。填写出现的表格,然后单击“继续”。下载的文件将具有
.zip
扩展名。解压文件以提取.ova 或.ovf
文件:
在 Cloudera Quickstart 下载选项上选择 Virtualbox
我们得到以下登录屏幕:
CDH 注册屏幕
首先列出了条款和条件:
CDH 许可条款接受
CDH 的 VM 下载开始:
CDH VM 超过 5GB,可能需要一段时间来下载
解压文件。文件夹中将包含以下图像中显示的文件:
如果文件是 Zip 格式,则解压文件
下载文件超过 5GB,根据您的互联网连接速度,可能需要一些时间
- 下载完成后,双击
.ova 或.ovf
文件,它将在 Oracle VirtualBox 中打开:
在 Virtualbox 中为 VM 选择选项
您还可以通过启动 Oracle VirtualBox 手动打开文件,转到文件|导入虚拟设备,并选择您下载的.ova/.ovf
文件作为要导入的设备。
保持所有选项默认,并单击导入按钮,这将开始导入过程。在此阶段,Cloudera CDH Quickstart VM 正在加载到您的 Oracle VirtualBox 环境中。
- 导入文件后,您可以通过单击窗口顶部的绿色箭头来启动它:
已加载 CDH VM 的 Oracle Virtualbox
- 在 OS 初始化时保持默认设置:
CDH 主 OS 页面
我们在安装的最后一步中得到以下屏幕:
CDH 网页管理 Hadoop 和其他 CDH 组件
这结束了使用 Hortonworks 数据平台安装 Hadoop 环境的安装。
在其他环境中安装 CDH
CDH Quickstart VM 也可以在 VMWare、Docker 和云平台上安装。有关相同的说明可在以下页面提供的链接中找到。
安装 Packt 数据科学 Box
我们还为书中的一些练习创建了一个单独的虚拟机。
从gitlab.com/packt_public/vm
下载 Packt 数据科学虚拟机 Vagrant 文件。
要加载 VM,首先从www.vagrantup.com/downloads.html
下载Vagrant。
Vagrant 的下载页面
完成下载后,通过运行下载的 Vagrant 安装文件来安装Vagrant。安装完成后,您将收到重新启动计算机的提示。重新启动系统,然后继续加载 vagrant 文件的下一步:
完成 Vagrant 安装
在最后一步上点击确认以重新启动:
重新启动系统
在终端或命令提示符中,转到您下载了 Packt 数据科学 Vagrant 文件的目录,并运行以下命令(在 Windows 中显示):
$ vagrant box add packtdatascience packtdatascience.box ==> box: Box file was not detected as metadata. Adding it directly...
==> box: Adding box 'packtdatascience' (v0) for provider:
box: Unpacking necessary files from: file://C:/Users/packt/Downloads/packt_public_vm/packtdatascience.box
box: Progress: 100% (Rate: 435M/s, Estimated time remaining: --:--:--)
==> box: Successfully added box 'packtdatascience' (v0) for 'virtualbox'! $ vagrant box list packtdatascience (virtualbox, 0)
C:UsersNataraj DasguptaDownloadspackt_public_vm>vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'packtdatascience'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: packt_public_vm_default_1513453154192_57570
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
default: Adapter 1: nat
==> default: Forwarding ports...
default: 22 (guest) => 2222 (host) (adapter 1)
==> default: Booting VM...
...
如果一切顺利,您应该在 Oracle VirtualBox 中看到一个新条目:
已加载 Packt 数据科学 VM 的 Oracle Virtualbox
双击框的名称以启动(和测试)它。使用 id/password 登录为packt/packt
:
Packt VM 的登录屏幕
安装 Spark
CDH Quickstart VM 包括 Spark 作为其中一个组件,因此不需要单独安装 Spark。我们将在专门讨论 Spark 的章节中更多地讨论 Spark。
此外,我们关于 Spark 的教程将使用 Databricks 社区版,可以从community.cloud.databricks.com/
访问。有关创建帐户和执行必要步骤的说明已在第六章中提供,用于大数据分析的 Spark。
安装 R
R 是一种统计语言,在过去 3-5 年中变得非常流行,特别是作为一个可以用于各种用例的平台,从简单的数据挖掘到复杂的机器学习算法。根据 2016 年中期 IEEE Spectrum 发布的一篇文章,R 在世界排名前 10 的语言中排名第 5。
可以从www.r-project.org
的 CRAN 网站上下载开源 R,该网站位于cran.r-project.org/mirrors.html
。
或者,您可以从mran.microsoft.com/rro/
的 Microsoft R Open 页面下载 R。 这以前被称为 Revolution R Open,是由 Revolution Analytics 发布的增强版本的开源 R。 在 2015 年 Microsoft 收购 Revolution Analytics 后,它在新所有权下进行了重新品牌。
Microsoft R Open 包括 R 的所有功能,还包括以下功能:
-
默认安装了许多 R 软件包,以及由 Microsoft Corporation 发布的一组专业软件包,这些软件包补充了开源 R 的现有功能
-
多线程数学库,用于 R 中的多线程计算
-
称为 MRAN 的固定 CRAN 存储库。 CRAN,全面的 R 存档网络是一个包含 R 二进制文件,软件包和相关内容的站点集合。 CRAN 上的软件包可以持续更新。 MRAN 获取 CRAN 的固定快照,直到下一个发布保持不变,从而实现可重现性和一致性。
下载并安装 Microsoft R Open 的步骤
我们按照以下步骤进行:
- 前往
mran.microsoft.com
并点击立即下载按钮:
Microsoft 开放 R 主页
- 选择适合您系统的发行版(Windows,macOS 或 Linux):
Microsoft 开放 R 版本
-
下载完成后,双击下载的文件安装Microsoft R Open。
-
请注意,在 macOS 上,您可能会收到以下错误消息:
OS X 消息(使用下面的方法绕过)
- 如果发生这种情况,请右键单击下载的文件,然后从弹出的菜单中选择“打开”。 这将允许您手动打开文件并安装:
绕过 OS X 之前显示的消息
- 安装后,双击Microsoft R Open启动应用程序:
Microsoft R 控制台
安装 RStudio
RStudio 是由rstudio.org发布的应用程序,提供了功能强大且功能丰富的图形IDE(集成开发环境)。
以下是安装 RStudio 的步骤:
R Studio 版本
- 点击与您的操作系统相关的链接,下载并安装相应的文件:
下载 RStudio
- 请注意,在 macOS 上,您可以简单地将下载的文件移动到应用程序文件夹。 在 Windows 和 Linux 操作系统上,双击下载的文件以完成安装文件的步骤:
在 Mac 上安装 RStudio(复制到应用程序文件夹)
安装 Python
我们按照以下步骤进行安装:
-
与 R 类似,Python 因其多功能和多样化的软件包而备受欢迎。 Python 通常作为大多数现代基于 Linux 的操作系统的一部分提供。 对于我们的练习,我们将使用 Continuum Analytics®的 Anaconda,它通过许多数据挖掘和机器学习相关的软件包本地安装作为平台的一部分,增强了基本的开源 Python 提供。 这消除了从业者手动下载和安装软件包的需要。 在这方面,它在精神上与 Microsoft R Open 类似。 正如 Microsoft R 增强了基本的开源 R 提供的附加功能一样,Anaconda 改进了基本的开源 Python 提供的功能,以提供新的功能。
-
安装 Anaconda Python 的步骤
Python Anaconda 主页
- 下载适合您系统的发行版。请注意,我们将下载 Python v2.7(而不是 3.x 版本):
选择 Python Anaconda 安装程序
- 安装完成后,您应该能够打开终端窗口(或 Windows 中的命令窗口)并输入 Python,这将启动 Anaconda:
在控制台中启动 Python Anaconda
安装 Hadoop(CDH)、Spark、R 和 Python 的过程到此结束。在后面的章节中,我们将更详细地研究这些平台。
总结
本章介绍了一些用于数据科学的关键工具。特别是,它演示了如何下载和安装 Cloudera Hadoop 分发(CDH)、Spark、R、RStudio 和 Python 的虚拟机。虽然用户可以下载 Hadoop 的源代码并安装在 Unix 系统上,但通常会出现问题,并且需要大量的调试。使用虚拟机可以让用户在最小的努力下开始使用和学习 Hadoop,因为它是一个完全预配置的环境。
此外,R 和 Python 是机器学习和一般分析中最常用的两种语言。它们适用于所有流行的操作系统。虽然它们可以安装在虚拟机中,但鼓励用户尝试在本地机器(笔记本电脑/工作站)上安装它们,如果可行的话,因为这样性能会相对更高。
在下一章中,我们将更深入地了解 Hadoop 及其核心组件和概念的细节。
第四章:使用 Hadoop 的大数据
Hadoop 已经成为大数据世界的事实标准,特别是在过去三到四年里。 Hadoop 于 2006 年作为 Apache Nutch 的一个子项目开始,并引入了与分布式文件系统和分布式计算相关的两个关键功能,也被称为 MapReduce,这在开源社区中迅速流行起来。 今天,已经开发出了数千种利用 Hadoop 核心功能的新产品,并且它已经发展成一个包含 150 多种相关主要产品的庞大生态系统。可以说,Hadoop 是启动大数据和分析行业的主要催化剂之一。
在本章中,我们将讨论 Hadoop 的背景和核心概念,Hadoop 平台的组件,并深入了解 Hadoop 生态系统中的主要产品。 我们将了解分布式文件系统和分布式处理的核心概念,以及优化以提高 Hadoop 部署性能。 我们将以使用Cloudera Hadoop Distribution(CDH)进行真实世界的实践来结束。 我们将涵盖的主题有:
-
Hadoop 的基础知识
-
Hadoop 的核心组件
-
Hadoop 1 和 Hadoop 2
-
Hadoop 分布式文件系统
-
使用 MapReduce 的分布式计算原理
-
Hadoop 生态系统
-
Hadoop 生态系统概述
-
Hive,HBase 等
-
Hadoop 企业部署
-
内部部署
-
云部署
-
Cloudera Hadoop 的实践
-
使用 HDFS
-
使用 Hive
-
使用 WordCount 的 MapReduce
Hadoop 的基础知识
在 2006 年,Hadoop 的创造者 Doug Cutting 正在 Yahoo!工作。 他积极参与了一个名为 Nutch 的开源项目,该项目涉及开发大规模网络爬虫。 从高层次上看,网络爬虫本质上是一种可以在互联网上以自动方式浏览和索引网页的软件。 直观地,这涉及对大量数据进行高效的管理和计算。 2006 年 1 月底,Doug 正式宣布了 Hadoop 的开始。 请求的第一行,仍然可以在issues.apache.org/jira/browse/INFRA-700
上找到,是Lucene PMC 已投票将 Nutch 的一部分拆分为一个名为 Hadoop 的新子项目。 因此,Hadoop 诞生了。
在开始时,Hadoop 有两个核心组件:Hadoop 分布式文件系统(HDFS)和 MapReduce。 这是 Hadoop 的第一次迭代,现在也被称为 Hadoop 1。 稍后,在 2012 年,添加了第三个组件,称为YARN(另一个资源协调器),它解耦了资源管理和作业调度的过程。 在更详细地探讨核心组件之前,了解 Hadoop 的基本前提将有所帮助:
Doug Cutting 在issues.apache.org/jira/browse/NUTCH-193
上发布了他打算将Nutch 分布式 FS(NDFS)和 MapReduce 分离到一个名为 Hadoop 的新子项目的意图。
Hadoop 的基本前提
Hadoop 的基本前提是,不是尝试在单个大型机器上执行任务,而是将任务细分为较小的段,然后将其委派给多个较小的机器。 这些所谓的较小机器然后会在自己的数据部分上执行任务。 一旦较小的机器完成了它们的任务,产生了它们被分配的任务的结果,那么这些单独的结果单元将被聚合以产生最终结果。
尽管在理论上,这可能看起来相对简单,但有各种技术考虑要牢记。 例如:
-
网络是否足够快,可以从每个单独的服务器收集结果?
-
每个单独的服务器是否能够从磁盘快速读取数据?
-
如果一个或多个服务器失败,我们是否必须重新开始?
-
如果有多个大任务,应该如何设置优先级?
在处理这种性质的分布式架构时,还有许多其他考虑因素。
Hadoop 的核心模块
Hadoop 的核心模块包括:
-
Hadoop Common:Hadoop 所需的库和其他常见的辅助工具
-
HDFS:存储数据的分布式、高可用、容错的文件系统
-
Hadoop MapReduce:涉及跨商品服务器(或节点)的分布式计算的编程范式
-
Hadoop YARN:作业调度和资源管理的框架
在这些核心组件中,YARN 于 2012 年推出,以解决 Hadoop 首次发布的一些缺点。Hadoop 的第一个版本(或者等效地说是 Hadoop 的第一个模型)使用 HDFS 和 MapReduce 作为其主要组件。随着 Hadoop 的流行,使用 MapReduce 提供的设施之外的设施的需求变得越来越重要。这,再加上一些其他技术考虑因素,导致了 YARN 的开发。
现在让我们来看一下之前列举的 Hadoop 的显著特点。
Hadoop 分布式文件系统 - HDFS
HDFS 构成了所有 Hadoop 安装的基础。文件,或者更一般地说是数据,存储在 HDFS 中,并由 Hadoop 的节点访问。
HDFS 执行两个主要功能:
-
命名空间:提供保存集群元数据的命名空间,即 Hadoop 集群中数据的位置
-
数据存储:作为 Hadoop 集群中使用的数据的存储
文件系统被称为分布式,因为数据存储在多台服务器上的块中。可以通过一个简单的例子直观地理解 HDFS。考虑一本由 A-Z 章组成的大书。在普通文件系统中,整本书将作为一个单独的文件存储在磁盘上。在 HDFS 中,这本书将被分割成更小的块,比如 A-H 章的一个块,I-P 章的另一个块,以及 Q-Z 章的第三个块。这些块然后存储在不同的机架(或者用这个类比来说是书架)上。此外,每一章都会被复制三次,这样每一章都会有三个副本。
假设整本书的大小是 1GB,每一章大约是 350MB:
HDFS 的书架类比
以这种方式存储书籍实现了一些重要的目标:
-
由于这本书已经被分成了三部分,每部分都被章节组复制了三次,这意味着我们的进程可以通过从不同服务器查询部分来并行读取书。这减少了 I/O 争用,非常适合并行使用的一个很好的例子。
-
如果任何一个机架不可用,我们可以从任何其他机架检索章节,因为每个章节在不同机架上都有多个副本。
-
如果我被分配的任务只需要访问单独的一章,比如说 B 章,我只需要访问对应 A-H 章的文件。由于对应 A-H 章的文件大小是整本书的三分之一,访问和读取文件的时间会更短。
-
其他好处,比如对不同章节组的选择性访问权限等,也是可能的。
这可能是对实际 HDFS 功能的过度简化的类比,但它传达了这项技术的基本原则 - 大文件被分割成块(块),并以高可用性冗余配置分布在多台服务器上。现在我们将更详细地看一下实际的 HDFS 架构:
Hadoop 的 HDFS 后端包括:
-
NameNode:这可以被认为是主节点。NameNode 包含集群元数据,并知道存储在哪个位置的数据 - 简而言之,它持有命名空间。它将整个命名空间存储在 RAM 中,当请求到达时,提供有关哪些服务器持有所需任务的数据的信息。在 Hadoop 2 中,可以有多个 NameNode。可以创建一个辅助节点作为辅助节点。因此,它不是备用 NameNode,而是帮助保持集群元数据最新的节点。
-
DataNode:DataNodes 是负责存储数据块并在收到新请求时执行计算操作的单独服务器。这些主要是低性能的商品服务器,资源和容量比存储集群元数据的 NameNode 要低。
HDFS 中的数据存储过程
以下几点应该能很好地说明数据存储过程:
HDFS 中的所有数据都是以块的形式写入的,通常大小为 128 MB。因此,一个大小为 512 MB 的单个文件将被分成四个块(4 * 128 MB)。然后将这些块写入 DataNodes。为了保持冗余和高可用性,每个块都会被复制以创建副本。一般来说,Hadoop 安装的复制因子为 3,表示每个数据块都会被复制三次。
这样可以保证冗余性,以便在其中一个服务器失败或停止响应时,始终有第二个甚至第三个副本可用。为了确保这个过程能够无缝运行,DataNode 将副本放在独立的服务器上,并且还可以确保数据中心不同机架上的服务器上放置块。这是因为即使所有副本都在独立的服务器上,但所有服务器都在同一个机架上,机架电源故障将意味着没有副本可用。
将数据写入 HDFS 的一般过程如下:
-
NameNode 收到一个请求,要求将新文件写入 HDFS。
-
由于数据必须以块或分块的形式写入,HDFS 客户端(发出请求的实体)开始将数据缓存到本地缓冲区,一旦缓冲区达到分配的块大小(例如 128 MB),它会通知 NameNode 准备好写入第一个数据块(分块)。
-
根据其对 HDFS 集群状态的了解,NameNode 会提供关于需要存储块的目标 DataNode 的信息。
-
HDFS 客户端将数据写入目标 DataNode,并在块的写入过程完成后通知 NameNode。
-
随后,目标 DataNode 开始将其数据块的副本复制到第二个 DataNode,后者将作为当前块的副本。
-
第二个 DataNode 完成写入过程后,它将数据块发送给第三个 DataNode。
-
这个过程重复进行,直到所有与数据(或等效地,文件)对应的块都被复制到不同的节点上。
请注意,块的数量将取决于文件大小。以下图示了数据在 5 个数据节点之间的分布。
主节点和数据节点
Hadoop 的第一个版本中的 HDFS 架构,也称为 Hadoop 1,具有以下特点:
-
单个 NameNode:只有一个 NameNode 可用,因此它也是单点故障,因为它存储了整个集群的元数据。
-
存储数据块的多个 DataNodes,处理客户端请求,并在数据块上执行 I/O 操作(创建、读取、删除等)。
-
Hadoop 的第二个版本中的 HDFS 架构,也被称为 Hadoop 2,提供了原始 HDFS 设计的所有优点,并添加了一些新特性,最显著的是具有多个可以充当主要和次要 NameNode 的 NameNode 的能力。其他功能包括具有多个命名空间以及 HDFS 联邦。
-
HDFS 联邦值得特别一提。来自
hadoop.apache.org
的以下摘录以非常精确的方式解释了这个主题:
NameNode 是联邦的;NameNode 是独立的,不需要彼此协调。DataNode 被用作所有 NameNode 的块的共同存储。每个 DataNode 在集群中注册。DataNode 发送周期性的心跳和块报告。
Secondary NameNode 并不是备用节点,它不能在 NameNode 不可用时执行与 NameNode 相同的任务。然而,它通过执行一些清理操作使得 NameNode 重新启动过程更加高效。
这些操作(例如将 HDFS 快照数据与数据更改信息合并)通常在 NameNode 重新启动时由 NameNode 执行,根据自上次重新启动以来的更改量,可能需要很长时间。然而,Secondary NameNode 可以在主 NameNode 仍在运行时执行这些清理操作,以便在重新启动时,主 NameNode 可以更快地恢复。由于 Secondary NameNode 基本上在定期间隔对 HDFS 数据执行检查点,因此它也被称为检查点节点。
Hadoop MapReduce
MapReduce 是 Hadoop 的一个重要特性,可以说是使其著名的最重要的特性之一。MapReduce 的工作原理是将较大的任务分解为较小的子任务。与将单个机器委派为计算大型任务不同,可以使用一组较小的机器来完成较小的子任务。通过以这种方式分配工作,相对于使用单机架构,任务可以更加高效地完成。
这与我们在日常生活中完成工作的方式并没有太大不同。举个例子会更清楚一些。
MapReduce 的直观介绍
让我们以一个假设的由 CEO、董事和经理组成的组织为例。CEO 想知道公司有多少新员工。CEO 向他的董事发送请求,要求报告他们部门的新员工数量。董事再向各自部门的经理发送请求,要求提供新员工的数量。经理向董事提供数字,董事再将最终值发送回 CEO。
这可以被认为是 MapReduce 的一个现实世界的例子。在这个类比中,任务是找到新员工的数量。CEO 并没有自己收集所有数据,而是委派给了董事和经理,他们提供了各自部门的数字,如下图所示:
MapReduce 的概念
在这个相当简单的场景中,将一个大任务(在整个公司中找到新员工)分解为较小的任务(每个团队中的新员工),然后重新聚合个体数字,类似于 MapReduce 的工作方式。
MapReduce 的技术理解
MapReduce,顾名思义,有一个映射阶段和一个减少阶段。映射阶段通常是对其输入的每个元素应用的函数,从而修改其原始值。
MapReduce 生成键值对作为输出。
键值对: 键值对建立了一种关系。例如,如果约翰今年 20 岁,一个简单的键值对可以是(约翰,20)。在 MapReduce 中,映射操作产生这样的键值对,其中有一个实体和分配给该实体的值。
在实践中,映射函数可能会复杂,并涉及高级功能。
减少阶段接收来自映射函数的键值输入,并执行汇总操作。例如,考虑包含学校不同年级学生年龄的映射操作的输出:
学生姓名 | 班级 | 年龄 |
---|---|---|
John | 年级 1 | 7 |
Mary | 年级 2 | 8 |
Jill | 年级 1 | 6 |
Tom | 年级 3 | 10 |
Mark | 年级 3 | 9 |
我们可以创建一个简单的键值对,例如取班级和年龄的值(可以是任何值,但我只是拿这些来提供例子)。在这种情况下,我们的键值对将是(年级 1,7),(年级 2,8),(年级 1,6),(年级 3,10)和(年级 3,9)。
然后可以将计算每个年级学生年龄平均值的操作定义为减少操作。
更具体地说,我们可以对输出进行排序,然后将与每个年级对应的元组发送到不同的服务器。
例如,服务器 A 将接收元组(年级 1,7)和(年级 1,6),服务器 B 将接收元组(年级 2,8),服务器 C 将接收元组(年级 3,10)和(年级 3,9)。然后,服务器 A、B 和 C 将找到元组的平均值并报告(年级 1,6.5),(年级 2,8)和(年级 3,9.5)。
请注意,在这个过程中有一个中间步骤,涉及将输出发送到特定服务器并对输出进行排序,以确定应将其发送到哪个服务器。事实上,MapReduce 需要一个洗牌和排序阶段,其中键值对被排序,以便每个减少器接收一组固定的唯一键。
在这个例子中,如果说,而不是三个服务器,只有两个,服务器 A 可以被分配为计算与年级 1 和 2 对应的键的平均值,服务器 B 可以被分配为计算年级 3 的平均值。
在 Hadoop 中,MapReduce 期间发生以下过程:
-
客户端发送任务请求。
-
NameNode 分配将执行映射操作和执行减少操作的 DataNodes(单独的服务器)。请注意,DataNode 服务器的选择取决于所需操作的数据是否位于服务器本地。数据所在的服务器只能执行映射操作。
-
DataNodes 执行映射阶段并产生键值(k,v)对。
当映射器生成(k,v)对时,它们根据节点分配的键发送到这些减少节点。键分配给服务器取决于分区函数,这可以是键的哈希值(这是 Hadoop 中的默认值)。
一旦减少节点接收到与其负责计算的键对应的数据集,它就应用减少函数并生成最终输出。
Hadoop 最大程度地利用了数据局部性。映射操作由本地保存数据的服务器执行,即在磁盘上。更准确地说,映射阶段将仅由持有文件对应块的服务器执行。通过委托多个独立节点独立执行计算,Hadoop 架构可以有效地执行非常大规模的数据处理。
块大小和映射器和减少器的数量
在 MapReduce 过程中的一个重要考虑因素是理解 HDFS 块大小,即文件被分割成的块的大小。需要访问某个文件的 MapReduce 任务将需要对表示文件的每个块执行映射操作。例如,给定一个 512MB 的文件和 128MB 的块大小,需要四个块来存储整个文件。因此,MapReduce 操作将至少需要四个映射任务,其中每个映射操作将应用于数据的每个子集(即四个块中的每一个)。
然而,如果文件非常大,比如需要 10,000 个块来存储,这意味着我们需要 10,000 个映射操作。但是,如果我们只有 10 台服务器,那么我们将不得不向每台服务器发送 1,000 个映射操作。这可能是次优的,因为它可能导致由于磁盘 I/O 操作和每个映射的资源分配设置而产生高惩罚。
所需的减少器数量在 Hadoop Wiki 上非常优雅地总结了(wiki.apache.org/hadoop/HowManyMapsAndReduces
)。
理想的减少器应该是最接近以下值的最佳值:
- 块大小的倍数 * 5 到 15 分钟之间的任务时间 * 创建尽可能少的文件
除此之外,很有可能你的减少器不太好。用户有极大的倾向使用一个非常高的值(“更多的并行性意味着更快!”)或一个非常低的值(“我不想超出我的命名空间配额!”)。这两种情况都同样危险,可能导致以下一种或多种情况:
- 下一个工作流程阶段的性能差 * 由于洗牌而导致性能差 * 由于过载了最终无用的对象而导致整体性能差 * 没有真正合理的原因而破坏磁盘 I/O * 由于处理疯狂数量的 CFIF/MFIF 工作而产生大量的网络传输
Hadoop YARN
YARN 是 Hadoop 2 中引入的一个模块。在 Hadoop 1 中,管理作业和监视它们的过程是由称为 JobTracker 和 TaskTracker 的进程执行的。运行 JobTracker 守护进程(进程)的 NameNodes 会将作业提交给运行 TaskTracker 守护进程(进程)的 DataNodes。
JobTracker 负责协调所有 MapReduce 作业,并作为管理进程、处理服务器故障、重新分配到新 DataNodes 等的中央管理员。TaskTracker 监视 DataNode 中本地作业的执行,并向 JobTracker 提供状态反馈,如下所示:
JobTracker 和 TaskTrackers
这种设计长时间以来运行良好,但随着 Hadoop 的发展,对更复杂和动态功能的需求也相应增加。在 Hadoop 1 中,NameNode,因此是 JobTracker 进程,管理作业调度和资源监控。如果 NameNode 发生故障,集群中的所有活动将立即停止。最后,所有作业都必须以 MapReduce 术语表示 - 也就是说,所有代码都必须在 MapReduce 框架中编写才能执行。
Hadoop 2 解决了所有这些问题:
-
作业管理、调度和资源监控的过程被解耦并委托给一个名为 YARN 的新框架/模块
-
可以定义一个辅助主 NameNode,它将作为主 NameNode 的辅助
-
此外,Hadoop 2.0 将容纳 MapReduce 以外的框架
-
Hadoop 2 不再使用固定的映射和减少插槽,而是利用容器
在 MapReduce 中,所有数据都必须从磁盘读取,这对于大型数据集的操作来说是可以接受的,但对于小型数据集的操作来说并不是最佳选择。事实上,任何需要非常快速处理(低延迟)、具有交互性的任务或需要多次迭代(因此需要多次从磁盘读取相同数据)的任务都会非常慢。
通过消除这些依赖关系,Hadoop 2 允许开发人员实现支持具有不同性能要求的作业的新编程框架,例如低延迟和交互式实时查询,机器学习所需的迭代处理,流数据处理等不同拓扑结构,优化,例如内存数据缓存/处理等。
出现了一些新术语:
-
ApplicationMaster:负责管理应用程序所需的资源。例如,如果某个作业需要更多内存,ApplicationMaster 将负责获取所需的资源。在这种情况下,应用程序指的是诸如 MapReduce、Spark 等应用执行框架。
-
容器:资源分配的单位(例如,1GB 内存和四个 CPU)。一个应用程序可能需要多个这样的容器来执行。ResourceManager 为执行任务分配容器。分配完成后,ApplicationMaster 请求 DataNodes 启动分配的容器并接管容器的管理。
-
ResourceManager:YARN 的一个组件,其主要作用是为应用程序分配资源,并作为 JobTracker 的替代品。ResourceManager 进程在 NameNode 上运行,就像 JobTracker 一样。
-
NodeManagers:NodeManagers 是 TaskTracker 的替代品,负责向 ResourceManager(RM)报告作业的状态,并监视容器的资源利用情况。
下图显示了 Hadoop 2.0 中 ResourceManager 和 NodeManagers 的高层视图:
Hadoop 2.0
Hadoop 2 中固有的显着概念已在下一图中说明:
Hadoop 2.0 概念
YARN 中的作业调度
大型 Hadoop 集群同时运行多个作业并不罕见。当有多个部门提交了多个作业时,资源的分配就成为一个重要且有趣的话题。如果说,A 和 B 两个部门同时提交了作业,每个请求都是为了获得最大可用资源,那么哪个请求应该优先获得资源呢?一般来说,Hadoop 使用先进先出(FIFO)策略。也就是说,谁先提交作业,谁就先使用资源。但如果 A 先提交了作业,但完成 A 的作业需要五个小时,而 B 的作业将在五分钟内完成呢?
为了处理作业调度中的这些细微差别和变量,已经实施了许多调度方法。其中三种常用的方法是:
-
FIFO:如上所述,FIFO 调度使用队列来优先处理作业。作业按照提交的顺序执行。
-
CapacityScheduler:CapacityScheduler 根据每个部门可以提交的作业数量分配值,其中部门可以表示用户的逻辑组。这是为了确保每个部门或组可以访问 Hadoop 集群并能够利用最少数量的资源。如果服务器上有未使用的资源,调度程序还允许部门根据每个部门的最大值设置超出其分配容量。因此,CapacityScheduler 的模型提供了每个部门可以确定性地访问集群的保证。
-
公平调度程序:这些调度程序试图在不同应用程序之间均匀平衡资源的利用。虽然在某个特定时间点上可能无法实现平衡,但通过随时间平衡分配,可以使用公平调度程序实现平均值更或多或少相似的目标。
这些以及其他调度程序提供了精细的访问控制(例如基于每个用户或每个组的基础)并主要利用队列来优先和分配资源。
Hadoop 中的其他主题
Hadoop 还有一些其他方面值得特别提及。由于我们已经详细讨论了最重要的主题,本节概述了一些其他感兴趣的主题。
加密
数据加密是根据官方规定对各种类型的数据进行的。在美国,要求符合 HIPAA 规定的规则,对识别患者信息的数据进行加密存储。HDFS 中的数据可以在静态状态(在磁盘上)和/或传输过程中进行加密。用于解密数据的密钥通常由密钥管理系统(KMS)管理。
用户认证
Hadoop 可以使用服务器的本机用户认证方法。例如,在基于 Linux 的机器上,用户可以根据系统/etc/passwd
文件中定义的 ID 进行身份验证。换句话说,Hadoop 继承了服务器端设置的用户认证。
通过 Kerberos 进行用户认证,这是一种跨平台的认证协议,在 Hadoop 集群中也很常见。Kerberos 基于授予用户临时权限的票据概念。可以使用 Kerberos 命令使票据无效,从而限制用户根据需要访问集群上的资源的权限。
请注意,即使用户被允许访问数据(用户认证),由于另一个名为授权的功能,他或她仍然可能受到访问数据的限制。该术语意味着即使用户可以进行身份验证并登录到系统,用户可能仅限于可以访问的数据。通常使用本机 HDFS 命令执行此级别的授权,以更改目录和文件所有权为指定的用户。
Hadoop 数据存储格式
由于 Hadoop 涉及存储大规模数据,因此选择适合您用例的存储类型至关重要。Hadoop 中可以以几种格式存储数据,选择最佳存储格式取决于您对读/写 I/O 速度的要求,文件可以按需压缩和解压缩的程度,以及文件可以被分割的容易程度,因为数据最终将被存储为块。
一些流行和常用的存储格式如下:
-
文本/CSV:这些是纯文本 CSV 文件,类似于 Excel 文件,但以纯文本格式保存。由于 CSV 文件包含每行的记录,因此将文件拆分为数据块是自然而然的。
-
Avro:Avro 旨在改善在异构系统之间高效共享数据。它使用数据序列化,将模式和实际数据存储在单个紧凑的二进制文件中。Avro 使用 JSON 存储模式和二进制格式存储数据,并将它们序列化为单个 Avro 对象容器文件。多种语言,如 Python、Scala、C/C++等,都有本机 API 可以读取 Avro 文件,因此非常适合跨平台数据交换。
-
Parquet:Parquet 是一种列式数据存储格式。这有助于提高性能,有时甚至显著提高性能,因为它允许按列存储和访问数据。直观地说,如果你正在处理一个包含 100 列和 100 万行的 1GB 文件,并且只想从这 100 列中查询数据,能够只访问单独的列会比访问整个文件更有效。
-
ORCFiles:ORC 代表优化的行列格式。从某种意义上说,它是对纯列格式(如 Parquet)的进一步优化。ORCFiles 不仅按列存储数据,还按行存储,也称为条带。因此,以表格格式存储的文件可以分割成多个较小的条带,其中每个条带包含原始文件的一部分行。通过这种方式分割数据,如果用户任务只需要访问数据的一个小部分,那么该过程可以查询包含数据的特定条带。
-
SequenceFiles:在 SequenceFiles 中,数据表示为键值对并以二进制序列化格式存储。由于序列化,数据可以以紧凑的二进制格式表示,不仅减小了数据大小,而且提高了 I/O。Hadoop,尤其是 HDFS,在存在多个小文件(如音频文件)时效率不高。SequenceFiles 通过允许将多个小文件存储为单个单元或 SequenceFile 来解决了这个问题。它们也非常适合可分割的并行操作,并且对于 MapReduce 作业总体上是高效的。
-
HDFS 快照:HDFS 快照允许用户以只读模式保存特定时间点的数据。用户可以在 HDFS 中创建快照,实质上是数据在那个时间点的副本,以便在以后需要时检索。这确保了在文件损坏或其他影响数据可用性的故障发生时可以恢复数据。在这方面,它也可以被视为备份。快照存储在一个.snapshot 目录中,用户在那里创建了它们。
-
节点故障处理:大型 Hadoop 集群可能包含数万个节点。因此,任何一天都可能发生服务器故障。为了让 NameNode 了解集群中所有节点的状态,DataNodes 向 NameNode 发送定期心跳。如果 NameNode 检测到服务器已经失败,即它停止接收心跳,它会将服务器标记为失败,并将本地服务器上的所有数据复制到新实例上。
Hadoop 3 中预期的新功能
在撰写本书时,Hadoop 3 处于 Alpha 阶段。关于 Hadoop 3 中将可用的新变化的详细信息可以在互联网上找到。例如,hadoop.apache.org/docs/current/
提供了关于架构新变化的最新信息。
Hadoop 生态系统
这一章应该被命名为 Apache 生态系统。像本节中将讨论的所有其他项目一样,Hadoop 是一个 Apache 项目。Apache 是一个开源项目的简称,由 Apache 软件基金会支持。它最初起源于 90 年代初开发的 Apache HTTP 服务器,并且今天是一个协作的全球倡议,完全由参与向全球技术社区发布开源软件的志愿者组成。
Hadoop 最初是 Apache 生态系统中的一个项目,现在仍然是。由于其受欢迎程度,许多其他 Apache 项目也直接或间接地与 Hadoop 相关联,因为它们支持 Hadoop 环境中的关键功能。也就是说,重要的是要记住,这些项目在大多数情况下可以作为独立产品存在,可以在没有 Hadoop 环境的情况下运行。它是否能提供最佳功能将是一个单独的话题。
在本节中,我们将介绍一些对 Hadoop 的增长和可用性产生了重大影响的 Apache 项目,如下图所示:
产品 | 功能 |
---|---|
Apache Pig | Apache Pig,也称为 Pig Latin,是一种专门设计用于通过简洁的语句表示 MapReduce 程序的语言,这些语句定义了工作流程。使用传统方法编写 MapReduce 程序,比如用 Java,可能会非常复杂,Pig 提供了一种简单的抽象来表达 MapReduce 工作流程和复杂的抽取-转换-加载(ETL)过程。Pig 程序通过 Grunt shell 执行。 |
Apache HBase | Apache HBase 是一个分布式列式数据库,位于 HDFS 之上。它是基于 Google 的 BigTable 模型设计的,其中数据以列格式表示。HBase 支持跨数十亿条记录的表的低延迟读写,并且非常适合需要直接随机访问数据的任务。更具体地说,HBase 以三个维度索引数据 - 行、列和时间戳。它还提供了一种表示具有任意列数的数据的方法,因为列值可以在 HBase 表的单元格中表示为键值对。 |
Apache Hive | Apache Hive 提供了类似 SQL 的方言来查询存储在 HDFS 中的数据。Hive 将数据以序列化的二进制文件形式存储在 HDFS 中的类似文件夹的结构中。与传统数据库管理系统中的表类似,Hive 以表格格式存储数据,根据用户选择的属性在 HDFS 中进行分区。因此,分区是高级目录或表的子文件夹。概念上提供了第三层抽象,即桶,它引用 Hive 表的分区中的文件。 |
Apache Sqoop | Sqoop 用于从传统数据库中提取数据到 HDFS。因此,将数据存储在关系数据库管理系统中的大型企业可以使用 Sqoop 将数据从其数据仓库转移到 Hadoop 实现中。 |
Apache Flume | Flume 用于管理、聚合和分析大规模日志数据。 |
Apache Kafka | Kafka 是一个基于发布/订阅的中间件系统,可用于实时分析和随后将流数据(在 HDFS 中)持久化。 |
Apache Oozie | Oozie 是一个用于调度 Hadoop 作业的工作流管理系统。它实现了一个称为有向无环图(DAG)的关键概念,这将在我们关于 Spark 的部分中讨论。 |
Apache Spark | Spark 是 Apache 中最重要的项目之一,旨在解决 HDFS-MapReduce 模型的一些缺点。它最初是加州大学伯克利分校的一个相对较小的项目,迅速发展成为用于分析任务的 Hadoop 最重要的替代方案之一。Spark 在行业中得到了广泛的应用,并包括其他各种子项目,提供额外的功能,如机器学习、流式分析等。 |
CDH 实战
在本节中,我们将利用 CDH QuickStart VM 来学习本章讨论的一些主题。这些练习不一定要按照时间顺序进行,并且不依赖于完成其他练习。
我们将在本节中完成以下练习:
-
使用 Hadoop MapReduce 进行词频统计
-
使用 HDFS
-
使用 Apache Hive 下载和查询数据
使用 Hadoop MapReduce 进行词频统计
在本练习中,我们将尝试计算有史以来最长小说之一中每个单词的出现次数。对于本练习,我们选择了由乔治和/或玛德琳·德·斯库德里(Georges and/or Madeleine de Scudéry)于 1649-1653 年间编写的书籍《Artamène ou le Grand Cyrus》。该书被认为是有史以来第二长的小说,根据维基百科上相关列表(en.wikipedia.org/wiki/List_of_longest_novels
)。这部小说共有 10 卷,共计 13,905 页,约有两百万字。
首先,我们需要在 VirtualBox 中启动 Cloudera Distribution of Hadoop Quickstart VM,并双击 Cloudera Quickstart VM 实例:
启动需要一些时间,因为它初始化所有与 CDH 相关的进程,如 DataNode、NameNode 等:
一旦进程启动,它将启动一个默认的着陆页,其中包含与 Hadoop 相关的许多教程的引用。在本节中,我们将在 Unix 终端中编写我们的 MapReduce 代码。从左上角菜单中启动终端,如下截图所示:
现在,我们必须按照以下步骤进行:
-
创建一个名为
cyrus
的目录。这是我们将存储包含书文本的所有文件的地方。 -
按照第 4 步所示运行
getCyrusFiles.sh
。这将把书下载到cyrus
目录中。 -
按照所示运行
processCyrusFiles.sh
。该书包含各种 Unicode 和不可打印字符。此外,我们希望将所有单词改为小写,以忽略相同但具有不同大小写的单词的重复计数。 -
这将产生一个名为
cyrusprint.txt
的文件。该文件包含整本书的全部文本。我们将在这个文本文件上运行我们的 MapReduce 代码。 -
准备
mapper.py
和reducer.py
。顾名思义,mapper.py
运行 MapReduce 过程的映射部分。同样,reducer.py
运行 MapReduce 过程的减少部分。文件mapper.py
将文档拆分为单词,并为文档中的每个单词分配一个值为一的值。文件reducer.py
将读取mapper.py
的排序输出,并对相同单词的出现次数进行求和(首先将单词的计数初始化为一,并在每个新单词的出现时递增)。最终输出是一个包含文档中每个单词计数的文件。
步骤如下:
- 创建
getCyrusFiles.sh
- 此脚本将用于从网络中检索数据:
[cloudera@quickstart ~]$ mkdir cyrus
[cloudera@quickstart ~]$ vi getCyrusFiles.sh
[cloudera@quickstart ~]$ cat getCyrusFiles.sh
for i in `seq 10`
do
curl www.artamene.org/documents/cyrus$i.txt -o cyrus$i.txt
done
- 创建
processCyrusFiles.sh
- 此脚本将用于连接和清理在上一步中下载的文件:
[cloudera@quickstart ~]$ vi processCyrusFiles.sh
[cloudera@quickstart ~]$ cat processCyrusFiles.sh
cd ~/cyrus;
for i in `ls cyrus*.txt` do cat $i >> cyrusorig.txt; done
cat cyrusorig.txt | tr -dc '[:print:]' | tr A-Z a-z > cyrusprint.txt
- 更改权限为 755,以使
.sh
文件在命令提示符下可执行:
[cloudera@quickstart ~]$ chmod 755 getCyrusFiles.sh
[cloudera@quickstart ~]$ chmod 755 processCyrusFiles.sh
- 执行
getCyrusFiles.sh
:
[cloudera@quickstart cyrus]$ ./getCyrusFiles.sh
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 908k 100 908k 0 0 372k 0 0:00:02 0:00:02 --:--:-- 421k
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1125k 100 1125k 0 0 414k 0 0:00:02 0:00:02 --:--:-- 471k
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1084k 100 1084k 0 0 186k 0 0:00:05 0:00:05 --:--:-- 236k
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1048k 100 1048k 0 0 267k 0 0:00:03 0:00:03 --:--:-- 291k
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1116k 100 1116k 0 0 351k 0 0:00:03 0:00:03 --:--:-- 489k
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1213k 100 1213k 0 0 440k 0 0:00:02 0:00:02 --:--:-- 488k
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1119k 100 1119k 0 0 370k 0 0:00:03 0:00:03 --:--:-- 407k
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1132k 100 1132k 0 0 190k 0 0:00:05 0:00:05 --:--:-- 249k
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1084k 100 1084k 0 0 325k 0 0:00:03 0:00:03 --:--:-- 365k
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1259k 100 1259k 0 0 445k 0 0:00:02 0:00:02 --:--:-- 486k
[cloudera@quickstart cyrus]$ ls
cyrus10.txt cyrus3.txt cyrus6.txt cyrus9.txt
cyrus1.txt cyrus4.txt cyrus7.txt getCyrusFiles.sh
cyrus2.txt cyrus5.txt cyrus8.txt processCyrusFiles.sh
- 执行
processCyrusFiles.sh
:
[cloudera@quickstart cyrus]$ ./processCyrusFiles.sh
[cloudera@quickstart cyrus]$ ls
cyrus10.txt cyrus3.txt cyrus6.txt cyrus9.txt getCyrusFiles.sh
cyrus1.txt cyrus4.txt cyrus7.txt cyrusorig.txt processCyrusFiles.sh
cyrus2.txt cyrus5.txt cyrus8.txt cyrusprint.txt
[cloudera@quickstart cyrus]$ ls -altrh cyrusprint.txt
-rw-rw-r-- 1 cloudera cloudera 11M Jun 28 20:02 cyrusprint.txt
[cloudera@quickstart cyrus]$ wc -w cyrusprint.txt
1953931 cyrusprint.txt
- 执行以下步骤,将最终文件
cyrusprint.txt
复制到 HDFS,创建mapper.py
和reducer.py
脚本。
mapper.py
和reducer.py
文件在 Glenn Klockwood 的网站上有引用(www.glennklockwood.com/data-intensive/hadoop/streaming.html
),该网站提供了大量关于 MapReduce 和相关主题的信息。
以下代码显示了mapper.py
的内容:
[cloudera@quickstart cyrus]$ hdfs dfs -ls /user/cloudera
[cloudera@quickstart cyrus]$ hdfs dfs -mkdir /user/cloudera/input
[cloudera@quickstart cyrus]$ hdfs dfs -put cyrusprint.txt /user/cloudera/input/
[cloudera@quickstart cyrus]$ vi mapper.py
[cloudera@quickstart cyrus]$ cat mapper.py
#!/usr/bin/env python
#the above just indicates to use python to intepret this file
#This mapper code will input a line of text and output <word, 1> #
import sys
sys.path.append('.')
for line in sys.stdin:
line = line.strip()
keys = line.split()
for key in keys:
value = 1
print ("%s\t%d" % (key,value))
[cloudera@quickstart cyrus]$ vi reducer.py # Copy-Paste the content of reducer.py as shown below using the vi or nano Unix editor.
[cloudera@quickstart cyrus]$ cat reducer.py
#!/usr/bin/env python
import sys
sys.path.append('.')
last_key = None
running_total = 0
for input_line in sys.stdin:
input_line = input_line.strip()
this_key, value = input_line.split("\t", 1)
value = int(value)
if last_key == this_key:
running_total += value
else:
if last_key:
print("%s\t%d" % (last_key, running_total))
running_total = value
last_key = this_key
if last_key == this_key:
print( "%s\t%d" % (last_key, running_total) )
[cloudera@quickstart cyrus]$ chmod 755 *.py
- 执行 mapper 和 reducer 脚本,执行 MapReduce 操作以产生词频统计。您可能会看到如下所示的错误消息,但出于本练习的目的(以及为了生成结果),您可以忽略它们:
[cloudera@quickstart cyrus]$ hadoop jar /usr/lib/hadoop-mapreduce/hadoop-streaming.jar -input /user/cloudera/input -output /user/cloudera/output -mapper /home/cloudera/cyrus/mapper.py -reducer /home/cloudera/cyrus/reducer.py
packageJobJar: [] [/usr/lib/hadoop-mapreduce/hadoop-streaming-2.6.0-cdh5.10.0.jar] /tmp/streamjob1786353270976133464.jar tmpDir=null
17/06/28 20:11:21 INFO client.RMProxy: Connecting to ResourceManager at /0.0.0.0:8032
17/06/28 20:11:21 INFO client.RMProxy: Connecting to ResourceManager at /0.0.0.0:8032
17/06/28 20:11:22 INFO mapred.FileInputFormat: Total input paths to process : 1
17/06/28 20:11:22 INFO mapreduce.JobSubmitter: number of splits:2
17/06/28 20:11:23 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1498704103152_0002
17/06/28 20:11:23 INFO impl.YarnClientImpl: Submitted application application_1498704103152_0002
17/06/28 20:11:23 INFO mapreduce.Job: The url to track the job: http://quickstart.cloudera:8088/proxy/application_1498704103152_0002/
17/06/28 20:11:23 INFO mapreduce.Job: Running job: job_1498704103152_0002
17/06/28 20:11:30 INFO mapreduce.Job: Job job_1498704103152_0002 running in uber mode : false
17/06/28 20:11:30 INFO mapreduce.Job: map 0% reduce 0%
17/06/28 20:11:41 INFO mapreduce.Job: map 50% reduce 0%
17/06/28 20:11:54 INFO mapreduce.Job: map 83% reduce 0%
17/06/28 20:11:57 INFO mapreduce.Job: map 100% reduce 0%
17/06/28 20:12:04 INFO mapreduce.Job: map 100% reduce 100%
17/06/28 20:12:04 INFO mapreduce.Job: Job job_1498704103152_0002 completed successfully
17/06/28 20:12:04 INFO mapreduce.Job: Counters: 50
File System Counters
FILE: Number of bytes read=18869506
FILE: Number of bytes written=38108830
FILE: Number of read operations=0
FILE: Number of large read operations=0
FILE: Number of write operations=0
HDFS: Number of bytes read=16633042
HDFS: Number of bytes written=547815
HDFS: Number of read operations=9
HDFS: Number of large read operations=0
HDFS: Number of write operations=2
Job Counters
Killed map tasks=1
Launched map tasks=3
Launched reduce tasks=1
Data-local map tasks=3
Total time spent by all maps in occupied slots (ms)=39591
Total time spent by all reduces in occupied slots (ms)=18844
Total time spent by all map tasks (ms)=39591
Total time spent by all reduce tasks (ms)=18844
Total vcore-seconds taken by all map tasks=39591
Total vcore-seconds taken by all reduce tasks=18844
Total megabyte-seconds taken by all map tasks=40541184
Total megabyte-seconds taken by all reduce tasks=19296256
Map-Reduce Framework
Map input records=1
Map output records=1953931
Map output bytes=14961638
Map output materialized bytes=18869512
Input split bytes=236
Combine input records=0
Combine output records=0
Reduce input groups=45962
Reduce shuffle bytes=18869512
Reduce input records=1953931
Reduce output records=45962
Spilled Records=3907862
Shuffled Maps =2
Failed Shuffles=0
Merged Map outputs=2
GC time elapsed (ms)=352
CPU time spent (ms)=8400
Physical memory (bytes) snapshot=602038272
Virtual memory (bytes) snapshot=4512694272
Total committed heap usage (bytes)=391979008
Shuffle Errors
BAD_ID=0
CONNECTION=0
IO_ERROR=0
WRONG_LENGTH=0
WRONG_MAP=0
WRONG_REDUCE=0
File Input Format Counters
Bytes Read=16632806
File Output Format Counters
Bytes Written=547815
17/06/28 20:12:04 INFO streaming.StreamJob: Output directory: /user/cloudera/output
- 结果存储在 HDFS 中的
/user/cloudera/output
目录下,文件名以part-
为前缀:
[cloudera@quickstart cyrus]$ hdfs dfs -ls /user/cloudera/output
Found 2 items
-rw-r--r-- 1 cloudera cloudera 0 2017-06-28 20:12 /user/cloudera/output/_SUCCESS
-rw-r--r-- 1 cloudera cloudera 547815 2017-06-28 20:12 /user/cloudera/output/part-00000
- 要查看文件的内容,请使用
hdfs dfs -cat
并提供文件名。在这种情况下,我们查看输出的前 10 行:
[cloudera@quickstart cyrus]$ hdfs dfs -cat /user/cloudera/output/part-00000 | head -10
! 1206
!) 1
!quoy, 1
' 3
'' 1
'. 1
'a 32
'appelloit 1
'auoit 1
'auroit 10
使用 Hive 分析石油进口价格
在本节中,我们将使用 Hive 分析 1980-2016 年间世界各国的石油进口价格。数据可从OECD(经济合作与发展组织)的网站上获取,网址如下截图所示:
实际的 CSV 文件可从stats.oecd.org/sdmx-json/data/DP_LIVE/.OILIMPPRICE.../OECD?contentType=csv&detail=code&separator=comma&csv-lang=en
获取。
由于我们将在 Hive 中加载数据,因此通过 Cloudera Quickstart CDH 环境中的终端将文件下载到我们的主目录是有意义的。我们将执行以下步骤:
- 将 CSV 文件下载到 CDH 环境中:
# Download the csv file
cd /home/cloudera;
wget -O oil.csv "https://stats.oecd.org/sdmx-json/data/DP_LIVE/.OILIMPPRICE.../OECD?contentType=csv&detail=code&separator=comma&csv-lang=en"
- 清理 CSV 文件。数据清洗是数据科学中非常重要的领域。在实践中,经常会收到需要清洗的文件。这是因为列中可能包含无效字符或值、缺失数据、缺少或额外的分隔符等。我们注意到各种值都用双引号(")括起来。在 Hive 中,我们可以通过在创建表时指定
quoteChar
属性来忽略引号。由于 Linux 也提供了简单易行的方法来删除这些字符,我们使用sed
来删除引号:
[cloudera@quickstart ~]$ sed -i 's/\"//g' oil.csv
此外,在我们下载的文件oil.csv
中,我们观察到存在可能引起问题的不可打印字符。我们通过发出以下命令将它们删除:
[cloudera@quickstart ~]$ tr -cd '\11\12\15\40-\176' oil_.csv > oil_clean.csv
(来源:alvinalexander.com/blog/post/linux-unix/how-remove-non-printable-ascii-characters-file-unix
)
最后,我们将新文件(oil_clean.csv
)复制到oil.csv
。由于oil.csv
文件已存在于同一文件夹中,我们收到了覆盖消息,我们输入yes
:
[cloudera@quickstart ~]$ mv oil_clean.csv oil.csv
mv: overwrite `oil.csv'? yes
- 登录到 Cloudera Hue:
在浏览器的书签栏中点击 Hue。这将显示 Cloudera 登录界面。使用 IDcloudera
和密码cloudera
登录:
- 从 Hue 登录窗口的快速启动下拉菜单中选择 Hue:
- 创建表模式,加载 CSV 文件
oil.csv
,并查看记录:
CREATE TABLE IF NOT EXISTS OIL
(location String, indicator String, subject String, measure String,
frequency String, time String, value Float, flagCode String)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n'
STORED AS TEXTFILE
tblproperties("skip.header.line.count"="1");
LOAD DATA LOCAL INPATH '/home/cloudera/oil.csv' INTO TABLE OIL;
SELECT * FROM OIL;
-
加载石油文件。
-
现在表已加载到 Hive 中,您可以使用 HiveQL 运行各种 Hive 命令。这些命令的完整集合可在
cwiki.apache.org/confluence/display/Hive/LanguageManual
上找到。
例如,要查找 1980-2015 年(数据集的日期范围)每个国家的石油价格的最大值、最小值和平均值,我们可以使用熟悉的 SQL 运算符。查询如下:
SELECT LOCATION, MIN(value) as MINPRICE, AVG(value) as AVGPRICE,
MAX(value) as MAXPRICE
FROM OIL
WHERE FREQUENCY LIKE "A"
GROUP BY LOCATION;
以下是相同的截图:
类似地,我们可以使用一系列其他 SQL 命令。Hive 手册详细介绍了这些命令以及数据保存、查询和检索的各种方式。
Hue 包括一系列有用的功能,如数据可视化、数据下载等,允许用户对数据进行临时分析。
要访问可视化功能,请在结果部分的网格图标下方点击可视化图标,如下截图所示:
选择散点图。在 Hue 中,这种类型的图表,也被更普遍地称为散点图,允许用户非常容易地创建多变量图表。可以选择 x 和 y 轴的不同数值,以及散点大小和分组,如下截图所示:
以下是一个简单的饼图,可以通过在下拉菜单中选择饼图来构建:
在 Hive 中连接表格
Hive 支持高级连接功能。以下是使用左连接的过程。如图所示,原始表格中有每个国家的数据,用它们的三字母国家代码表示。由于 Hue 支持地图图表,我们可以添加纬度和经度的数值,将石油定价数据叠加在世界地图上。
为此,我们需要下载一个包含纬度和经度数值的数据集:
# ENTER THE FOLLOWING IN THE UNIX TERMINAL
# DOWNLOAD LATLONG CSV FILE
cd /home/cloudera;
wget -O latlong.csv "https://gist.githubusercontent.com/tadast/8827699/raw/7255fdfbf292c592b75cf5f7a19c16ea59735f74/countries_codes_and_coordinates.csv"
# REMOVE QUOTATION MARKS
sed -i 's/\"//g' latlong.csv
一旦文件被下载和清理,就在 Hive 中定义模式并加载数据:
CREATE TABLE IF NOT EXISTS LATLONG
(country String, alpha2 String, alpha3 String, numCode Int, latitude Float, longitude Float)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n'
STORED AS TEXTFILE
TBLPROPERTIES("skip.header.line.count"="1");
LOAD DATA LOCAL INPATH '/home/cloudera/latlong.csv' INTO TABLE LATLONG;
将石油数据与纬度/经度数据进行连接:
SELECT DISTINCT * FROM
(SELECT location, avg(value) as AVGPRICE from oil GROUP BY location) x
LEFT JOIN
(SELECT TRIM(ALPHA3) AS alpha3, latitude, longitude from LATLONG) y
ON (x.location = y.alpha3);
现在我们可以开始创建地理空间可视化。请记住,这些是在 Hue 中提供非常方便的查看数据的初步可视化。可以使用 shapefile、多边形和其他高级图表方法在地理数据上开发更深入的可视化。
从下拉菜单中选择渐变地图,并输入适当的数值来创建图表,如下图所示:
下一个图表是使用下拉菜单中的标记地图选项开发的。它使用三个字符的国家代码来在相应的区域放置标记和相关数值,如下图所示:
总结
本章提供了 Hadoop 的技术概述。我们讨论了 Hadoop 的核心组件和核心概念,如 MapReduce 和 HDFS。我们还研究了使用 Hadoop 的技术挑战和考虑因素。虽然在概念上可能看起来很简单,但 Hadoop 架构的内部运作和正式管理可能相当复杂。在本章中,我们强调了其中一些。
我们以使用 Cloudera Distribution 的 Hadoop 进行了实际操作的方式结束。对于本教程,我们使用了之前从 Cloudera 网站下载的 CDH 虚拟机。
在下一章中,我们将看一下 NoSQL,这是 Hadoop 的一个替代或补充解决方案,取决于您个人和/或组织的需求。虽然 Hadoop 提供了更丰富的功能集,但如果您的预期用例可以简单地使用 NoSQL 解决方案,后者可能是在所需的努力方面更容易的选择。
第五章:使用 NoSQL 进行大数据挖掘
术语NoSQL最初是由 Carlo Strozzi 使用的,他在 1998 年发布了 Strozzi NoSQL 开源关系数据库。在 2000 年代末,数据库架构中出现了新的范式,其中许多范式不符合关系数据库系统所需的严格约束。由于这些数据库不符合 ACID 兼容性等标准数据库约定,它们很快被归为一个称为 NoSQL 的广泛类别。
每个 NoSQL 数据库都声称对某些用例最优。虽然其中很少有适合成为通用数据库管理系统的要求,但它们都在整个 NoSQL 系统范围内利用了一些共同的主题。
在本章中,我们将讨论 NoSQL 数据库管理系统的一些广泛类别。我们将讨论引发迁移到 NoSQL 数据库系统的主要驱动因素,以及这些数据库如何解决导致它们广泛采用的特定业务需求,并最后进行一些 NoSQL 实际练习。
本章涵盖的主题包括:
-
为什么选择 NoSQL?
-
NoSQL 数据库
-
内存数据库
-
列式数据库
-
面向文档的数据库
-
键值数据库
-
图数据库
-
其他 NoSQL 类型和总结
-
NoSQL 系统的实际练习
为什么选择 NoSQL?
术语 NoSQL 通常意味着不仅仅是 SQL:也就是说,底层数据库具有与常见和传统数据库系统不同的属性。因此,除了它们不提供 ACID 兼容性的特征之外,没有明确的区分资格数据库作为 NoSQL 的标准。因此,了解 ACID 属性的性质将有助于理解数据库系统多年来的主要特点,以及简要讨论 BASE 和 CAP 的重要性,这两个术语是当今数据库的核心术语。
ACID、BASE 和 CAP 属性
让我们首先讨论 ACID 和 SQL。
ACID 和 SQL
ACID 代表原子性、一致性、隔离性和持久性:
-
原子性:这表示数据库事务要么完全执行,要么根本不执行。换句话说,要么所有事务都应该被提交,即完全持久化,要么根本不提交。没有部分执行事务的余地。
-
一致性:对数据的约束,即确定数据库内数据管理的规则,将在整个数据库中保持一致。不同的实例不会遵守与数据库其他实例不同的规则。
-
隔离性:此属性定义了并发操作(事务)如何读取和写入数据的规则。例如,如果某个记录正在被更新,而另一个进程读取同一条记录,数据库系统的隔离级别将决定返回给用户的数据版本。
-
持久性:数据库系统的持久性通常表示已提交的事务即使在系统故障的情况下也将保持持久。这通常通过数据库可以在恢复期间参考的事务日志来管理。
读者可能会注意到这里定义的所有属性主要与数据库事务有关。事务是遵守上述规则并对数据库进行更改的操作单元。例如,从 ATM 机中典型的取款可能有以下逻辑路径:
-
用户从 ATM 机中取款
-
银行检查用户的当前余额
-
数据库系统从用户的账户中扣除相应的金额
-
数据库系统更新用户账户中的金额以反映变化
因此,在 1990 年代中期之前广泛使用的大多数数据库,如 Oracle、Sybase、DB2 等,都针对记录和管理事务数据进行了优化。直到这个时候,大多数数据库都负责管理事务数据。90 年代中期互联网的快速增长导致出现了新类型的数据,这些数据不一定需要严格的 ACID 兼容性要求。YouTube 上的视频、Pandora 上的音乐和企业电子邮件记录都是事务数据库不会增加价值的用例的例子,除了作为存储数据的技术层之外。
NoSQL 的 BASE 属性
到了 2000 年代末,数据量激增,显然需要一种新的替代模型来管理数据。这种新模型称为 BASE,成为取代 ACID 成为首选数据库管理系统模型的基础主题。
BASE代表Basically Available Soft-state Eventually consistency。这意味着数据库基本上大部分时间都可以使用;也就是说,可能会有一段时间服务不可用(因此应该实施额外的冗余措施)。Soft-state意味着系统的状态不能保证 - 相同数据的不同实例可能具有不同的内容,因为它可能还没有捕获集群另一部分的最新更新。最后,eventually consistent 意味着尽管数据库可能并非始终处于相同状态,但最终会达到相同状态;也就是说,变得consistent。
CAP 定理
CAP 定理由 Eric Allen Brewer 于 1990 年代末首次提出,它对分布式数据库系统的约束或更一般地说特征进行了分类。简而言之,CAP 定理假设严格来说,数据库系统只能保证 CAP 定义的三个属性中的两个。
-
一致性:数据应该在数据库的所有实例中保持一致,因此,在查询时应该在所有节点上提供一致的结果
-
可用性:无论任何单个节点的状态如何,系统在执行查询时始终会响应结果(无论是否是最新提交)
-
分区容错性:这意味着当节点在网络上分离时,系统应该继续正常运行,即使任何节点失去与另一个节点的互联性
从这一点可以看出,在集群中,节点将通过网络连接,而网络本质上是可以中断的,因此必须保证分区容错性,以便系统能够继续正常运行。在这种情况下,争议在于选择一致性和可用性之间。例如,如果系统必须保持一致;也就是说,在所有节点上显示最新的提交,所有节点不能同时可用,因为一些节点可能没有最新的提交。在这种情况下,对新更新的查询将不会执行,直到所有节点都已更新为新数据。在可用性的情况下,以类似的术语,我们无法保证一致性,因为始终可用意味着一些节点将不具有与另一个节点相同的数据,如果新的更新尚未写入到相应的节点上。
在决定是确保一致性还是确保可用性之间存在很大的混乱和争议,因此数据库被分类为CP或AP。对于这个练习,我们不需要陷入术语,因为那将导致一场相当抽象和哲学的讨论。上述术语的信息主要是为了反映一些驱动数据库开发的基础理论。
NoSQL 技术的需求
虽然大多数数据库系统最初是为了管理事务而设计的,但互联网相关技术的增长和不需要事务系统严格净化性质的新类型数据的增长,促使了替代框架的发展。
例如,存储以下类型的数据不一定需要复杂的事务性数据库:
-
电子邮件
-
媒体文件,如音频/视频文件
-
社交网络消息
-
网站 HTML 页面
-
许多其他类型的数据
此外,用户数量的增加,以及因此而产生的数据量,表明需要开发具有以下特点的更加健壮的架构:
-
可扩展以管理不断增加的数据量
-
利用商品硬件减少对昂贵硬件的依赖
-
提供跨多个节点的分布式处理能力,以处理大规模数据集
-
具有容错能力/提供高可用性以处理节点和站点故障
可扩展意味着系统可以通过增加节点数量(即横向扩展)来容纳数据量的增加。此外,增加节点数量对系统性能的影响应该最小。
容错意味着系统应该能够处理节点故障,在一个拥有数百甚至数千个节点的大型分布式系统中,这种情况并不罕见。
这导致了各种具有突破性和影响力的系统的发展,其中最显著的可能是 Google Bigtable 和 Amazon Dynamo。
Google Bigtable
Bigtable 是一个于 2004 年启动的项目,旨在管理 Google 各种项目中使用的数据的可扩展性和性能。描述该系统特性的开创性论文于 2006 年发布(static.googleusercontent.com/media/research.google.com/en//archive/bigtable-osdi06.pdf
),标题为Bigtable: A Distributed Storage System for Structured Data。实质上,Bigtable 是一个列存储(稍后详述),其中每个值可以使用行键、列键和时间戳唯一标识。它是最早体现将数据存储在列格式而不是使用更常见的基于行的布局的数据库之一。尽管在 Bigtable 之前存在诸如 kdb+和 Sybase IQ 之类的列式数据库,但行业领先者使用该方法来管理 PB 级别信息的概念将该概念推上了舞台。
Bigtable 的官方网站总结了键值主张:
Bigtable 旨在以一致的低延迟和高吞吐量处理大规模工作负载,因此它是操作和分析应用的绝佳选择,包括物联网、用户分析和金融数据分析。
自从 Bigtable 推出以来,其他几个 NoSQL 数据库也采用了列式数据布局的惯例;其中最著名的是 HBase 和 Accumulo,它们都是 Apache 项目。
Bigtable 解决方案如今可以在cloud.google.com/bigtable/
上使用,并可以按订阅方式购买。较小数据量的费用相当低廉和合理,而更大的安装则需要更广泛的实施。
Amazon Dynamo
就在 Google 宣布 Bigtable 不久之后,亚马逊在 2007 年 10 月举办的第 21 届操作系统原理研讨会上宣布了其内部 Dynamo 数据库(www.sosp2007.org
)。
在这篇论文中,亚马逊描述了一种名为 Dynamo 的键值存储,该论文现在可以在 Werner Vogels 的网站上找到www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf
,Dynamo 被用于支持亚马逊 AWS 上的一些最关键的内部服务,如 S3。该论文提出了一些关键概念,如键值存储、一致性哈希和向量时钟等,这些概念在 Dynamo 中得到了实现。
因此,Dynamo 为大规模数据集的列存储提供了一种替代方案,引入了一种基本不同的方法,利用了键值关联。
在接下来的几节中,我们将讨论各种类型的 NoSQL 技术,以及它们各自具有使它们对某些用例最优的特性。NoSQL 已经引领了我们对待数据库的范式转变,并为以前不可行的规模提供了急需的数据管理替代视图。
NoSQL 数据库
在我们讨论 NoSQL 类型和数据库时,我们将主要关注 NoSQL 数据库的以下特性:
-
内存数据库
-
列式数据库
-
面向文档的数据库
-
键值数据库
-
图数据库
-
其他 NoSQL 类型和总结
今天在行业中使用的大多数 NoSQL 类型都属于这些类别中的一个或多个。接下来的几节将讨论每种 NoSQL 产品的高级特性、它们的主要优势以及市场上属于各自类别的产品。
内存数据库
内存数据库,顾名思义,利用计算机内存,即 RAM,来存储数据集。在我们研究内存数据库如何工作之前,值得回顾一下典型计算机中数据传输是如何发生的:
简单数据流计算机层次结构
如前图所示,数据从磁盘到内存到 CPU。这是对确切过程的非常高级的概括,因为在 CPU 不需要发送指令从内存读取数据的条件下(例如当数据已经存在于 CPU L2 缓存中 - 这是 CPU 中包含用于缓存数据的内存的一部分),但从根本上讲,CPU、RAM 和磁盘之间的过程是线性的。
存储在磁盘上的数据可以以取决于磁盘的 I/O(输入/输出)吞吐量的一定速率转移到内存。从磁盘访问数据大约需要 10-20 毫秒(ms)。虽然确切的数字取决于数据的大小,但最小的寻道时间(磁盘找到数据位置所需的时间)本身大约是 10-15 毫秒。将这与从内存获取数据所需的时间相比,大约是 100 纳秒。最后,从 CPU L2 缓存读取数据大约需要 7 纳秒。
为了形象地说明这一点,15 毫秒的磁盘访问时间,即 15,000,000 纳秒,比从内存访问数据所需的时间慢 150,000 倍。换句话说,相对于磁盘,已经存在于内存中的数据可以以惊人的速度读取,快 150,000 倍。这基本上是读取随机数据的情况。读取顺序数据的时间可能不那么引人注目,但仍然快近一个数量级。
如果将磁盘和 RAM 表示为汽车,RAM 汽车在磁盘汽车只能勉强行驶两英里的时间内已经到达月球并且正在返回的路上。这就是差距有多大。
因此,从这个自然地得出结论,如果数据存储在 RAM 中,特别是在较大数据集的情况下,访问时间将大大降低,因此数据处理的时间(至少在 I/O 级别上)将显着减少。
传统上,所有数据库数据都存储在磁盘上。随着互联网的出现,行业开始利用memcached,它提供了一种通过 API 将数据以键值对的形式存储在内存中的方法。例如,MySQL 数据库通常使用 memcached API 来将对象缓存在内存中,以优化读取速度并减少对主要(MySQL)数据库的负载。
然而,随着数据量的增加,使用数据库和 memcached 方法的复杂性开始显现,专门设计用于在内存中存储数据(有时同时存储在磁盘和内存中)的数据库正在迅速发展。
因此,内存数据库(如 Redis)开始取代 memcached 成为驱动网站的快速缓存存储。在 Redis 的情况下,尽管数据将以键值对的形式存储在内存中,但也有选项将数据持久化到磁盘上。这使其与严格的内存缓存解决方案(如 memcached)有所区别。
推动向内存数据库转变的主要因素可以总结如下:
-
通过传统的 MySQL + memcached 组合等方式来管理不断增加的数据量的复杂性,例如网站流量
-
降低了 RAM 成本,使购买更大容量的内存更加经济
-
整个行业都在朝着 NoSQL 技术发展,这导致了对新型创新数据库平台的增加关注和社区参与。
-
内存中更快的数据操作提供了一种减少 I/O 开销的方法,这在需要超快速、低延迟处理数据的情况下非常重要
如今,行业中提供内存功能的数据库的主要选择包括:
开源 | 商业 |
---|---|
Redis | Kdb+ |
memcacheDB | Oracle TimesTen |
Aerospike | SAP HANA |
VoltDB | HP Vertica |
Apache Ignite | Altibase |
Apache Geode | Oracle Exalytics |
MonetDB | MemSQL |
请注意,其中一些支持混合架构,数据可以同时存储在内存和磁盘中。一般来说,数据会从内存传输到磁盘以实现持久化。此外,一些商业内存数据库提供可以根据各自解决方案适用的许可证条款免费下载和使用的社区版本。在这些情况下,它们既是开源的,也是商业的。
列式数据库
列式数据库自 90 年代以来就存在,但在谷歌 Bigtable 发布后变得更加突出。它们本质上是一种存储数据的方法,可以以相对于基于行/元组的存储方式更快速和高效地查询非常大量的数据。
列式数据库的好处,或者更具体地说,独立存储每列数据,可以通过一个简单的例子来说明。
考虑一个包含 1 亿个家庭地址和电话号码的表。同时考虑一个简单的查询,要求用户找到纽约州 Albany 市中 1990 年后建造的家庭数量。我们将创建一个假设的表来说明按行和按列查询数据的差异。
硬件特性:
平均磁盘读取速度:每秒 200 MB
数据库特性:
表名:housedb
-
总行数=1 亿
-
纽约州的总行数=两百万
-
拥有纽约州 Albany 市的总行数=10,000
-
拥有纽约州 Albany 市和 YearBuilt > 1990 的总行数= 500
数据大小:
假设每行数据的大小如下:
-
PlotNumber,YearBuilt 各= 8 字节=总共 16 字节
-
所有者,地址,州和城市各= 12 字节=总共 48 字节
-
每行的净大小(字节)= 16 + 48 = 64 字节
请注意,实际大小将更大,因为还有其他考虑因素,如索引和其他表优化以及相关的开销,出于简单起见,我们不会在这里考虑。
我们还将假设列式数据库维护了一个隐式的行索引,允许在每个列向量中的特定索引处查询数据。
以下表显示了前 4 条记录:
PlotNumber | Owner | Address | State | City | YearBuilt |
---|---|---|---|---|---|
1 | John | 1 Main St. | WA | Seattle | 1995 |
2 | Mary | 20 J. Ave. | NY | Albany | 1980 |
3 | Jane | 5 45^(th) St. | NY | Rye Brook | 2001 |
4 | John | 10 A. Blvd. | CT | Stamford | 2010 |
总的来说,这张表有 1 亿条记录。最后几条记录如下所示:
PlotNumber | Owner | Address | State | City | YearBuilt |
---|---|---|---|---|---|
99999997 | Jim | 23 B. Lane | NC | Cary | 1995 |
99999998 | Mike | 5 L. Street | NY | Syracuse | 1993 |
99999999 | Tim | 10 A. Blvd. | NY | Albany | 2001 |
100000000 | Jack | 10 A. Blvd. | CT | Stamford | 2010 |
我们将对这个数据集运行以下查询:
select * from housedb where State like 'NY' and City like 'Albany' and YearBuilt > 1990
场景 A:逐行搜索
在第一种情况下,如果我们进行天真的逐行搜索,由于每列的数据并未分开存储,而是扫描了每行的数据,我们将不得不查询以下内容:
1 亿 * 64 字节(每行的大小)= 6,400 万字节=大约 6000 MB 的数据
以 200 MBps 的磁盘读取速度来说,这意味着大约需要 6000 / 200 = 30 秒来读取所有记录以找到匹配的条目。
场景 B:逐列搜索
假设数据的每一列都存储在代表各自列的单独文件中,我们将逐个查找每个 where 子句:
select * from housedb where State like 'NY' and City like 'Albany' and YearBuilt > 1990
- Where clause part 1:
where State like 'NY'
如前所述,州列有 1 亿条记录,每条记录大小为 12 字节。
在这种情况下,我们只需要搜索以下内容:
1 亿 * 12 字节= 12 亿字节= 1000 MB 的数据。
以 200 MBps 的数据读取速率,这将花费 200 MB,读取列数据将花费 1000 / 200 = 5 秒。
这返回了两百万条记录(如前面所述的数据库特性)
- Where clause part 2:
City like 'Albany'
在前面的步骤中,我们已经将搜索范围缩小到满足 NY 州条件的两百万条记录。在第二个 where 子句步骤中,现在,我们不需要查询所有 1 亿条记录。相反,我们只需查看满足条件的两百万条记录,以确定哪些属于 Albany 市。
在这种情况下,我们只需要搜索以下内容:
2 百万 * 12 字节= 2400 万字节=大约 20 MB 的数据。
以 200 MBps 的数据读取速率,这将花费 0.1 秒。
这返回了 1 万条记录(如前面在数据库特性中提到的)。
- Where clause part 3:
YearBuilt > 1990
在前面的步骤中,我们进一步将搜索范围缩小到满足 NY 州和 Albany 市两个条件的 1 万条记录。在这一步中,我们将查询 1 万条 YearBuilt 列的记录,以确定哪些满足 YearBuilt > 1990 的条件。
在这种情况下,我们只需要搜索以下内容:
10,000 * 16 字节= 160,000 字节=大约 150 KB 的数据。
以 200 MBps 的数据读取速率,这将花费 0.00075 秒,我们可以四舍五入为零秒。
因此,在查询数据时花费的净时间为:
-
Where clause part 1:
where State like 'NY'
- 五秒 -
Where clause part 2:
City like 'Albany'
- 0.1 秒 -
Where clause part 3:
YearBuilt > 1990
- 零秒
读取数据所花费的净时间= 5.1 秒。
重要提示:实际的读取或更具体地说,扫描性能取决于各种其他因素。元组(行)的大小,重建元组的时间(元组重建),内存带宽(数据从主存储器读入 CPU 的速度等),缓存行大小和其他因素。在实践中,由于各种抽象级别,实际性能可能会较慢。此外,还有其他考虑因素,如硬件架构和并行操作,可以积极或否定地影响整体性能。这些主题更加深入,需要专门阅读。这里的分析专注于磁盘 I/O,这是整体性能的关键方面之一。
前面的示例演示了查询以列存储的数据的好处,从查询性能或效率的角度来看,这取决于数据的大小。列式数据还提供了另一个好处,即它允许以列的形式存储可能具有任意模式的表。
考虑前表的前四行。例如,如果某些行中有缺失信息,那将导致稀疏列:
PlotNumber | Owner | Address | State | City | YearBuilt |
---|---|---|---|---|---|
1 | John | 1 Main St. | NULL | 西雅图 | 1995 |
2 | Mary | 20 J. Ave. | 纽约 | NULL | NULL |
3 | Jane | NULL | 纽约 | 莱布鲁克 | NULL |
4 | John | 10 A. Blvd. | 康涅狄格 | NULL | NULL |
我们可以创建一个名为Complete_Address
的列族
,而不是填充 NULL 值,该列族可以包含与仅具有相应数据的字段对应的任意数量的键值对:
PlotNumber | Owner | Complete_Address | YearBuilt | |
---|---|---|---|---|
1 | John | 地址:1 Main St. | 城市:西雅图 | 1995 |
2 | Mary | 地址:20 J. Ave. | 州:纽约 | NULL |
3 | Jane | 州:纽约 | 城市:莱布鲁克 | NULL |
4 | John | 地址:10 A. Blvd. | 州:康涅狄格 | NULL |
列式数据库提供的第三个非常重要的好处是能够根据三个键检索数据:行键、列键和时间戳,这些键可以唯一标识每条记录,从而可以非常快速地访问所需的数据。
例如,由于所有权字段在财产(PlotNumber)出售时可能会更改,因此我们可以添加另一个字段,表示记录的日期;即记录对应的日期。这将允许我们区分在所有其他数据保持不变的情况下发生所有权变更的属性:
PlotNumber | Owner | Address | State | City | YearBuilt | RecordDate |
---|---|---|---|---|---|---|
1 | John | 1 Main St. | 华盛顿 | 西雅图 | 1995 | 2001.04.02 |
2 | Mary | 20 J. Ave. | 纽约 | 奥尔巴尼 | 1980 | 2007.05.30 |
3 | Jane | 5 45^(th) St. | 纽约 | 莱布鲁克 | 2001 | 2001.10.24 |
4 | John | 10 A. Blvd. | 康涅狄格 | 斯坦福 | 2010 | 2003.07.20 |
由于每个 PlotNumber 可以有多条记录以适应所有权的变更,我们现在可以定义三个键,可以唯一标识每条记录中每个数据单元,如下所示:
-
行键:
PlotNumber
-
列键:列名
-
时间戳键:
RecordDate
表中每条记录中的每个单元格都将具有一个唯一的三值对,用于将其与其他单元格区分开来。
诸如 Bigtable、Cassandra 等数据库采用这种方法,以便迅速高效地进行大规模数据分析。
以下是一些流行的列式数据库。请注意,由于数据库可以具有多个 NoSQL 属性(例如内存和列式),因此可能会有重复:
开源 | 商业 |
---|---|
Apache Parquet | Kdb+ |
MonetDB | Teradata |
MariaDB | SAP HANA |
Druid | HP Vertica |
HBase | Oracle Exadata |
Apache Kudu | ParAccel |
Apache Arrow | Actian Vector |
面向文档的数据库
基于文档或面向文档的数据库作为存储具有可变结构的数据的手段变得突出;也就是说,每条记录不一定总是符合固定模式。此外,文档可能既有结构化部分,也有非结构化部分。
结构化数据本质上是可以以表格格式存储的数据,比如电子表格中的数据。存储在 Excel 电子表格或 MySQL 表中的数据都属于结构化数据集的类别。无法以严格的表格格式表示的数据,比如书籍、音频文件、视频文件或社交网络消息,被视为非结构化数据。因此,在面向文档的数据库中,我们将主要处理结构化和非结构化文本数据。
一个直观的解释是,数据可以包含结构化和非结构化文本,可以在电话日记的例子中找到。尽管随着数字数据存储的增长,这些已经越来越少见,但我们中的许多人可能还记得电话号码写在口袋本上的时候。下面的图片展示了我们如何在电话日记中存储数据:
地址簿(半结构化数据集)
在上面的例子中,以下字段可以被视为结构化的:
-
姓名
-
地址
-
电话和传真
在地址字段下面有一行,用户可以输入任意信息,例如,在 2015 年的一次会议上见面,就职于 ABC 公司。这本质上是日记记录者在输入具体信息时写下的一条注释。由于这样的自由格式字段没有明确定义的特征,它也可能包含第二个电话号码,或者备用地址和其他信息。这将被视为非结构化文本。
此外,由于其他字段之间没有相互依赖,用户可以填写地址但不填写电话号码,或者填写姓名和电话号码但不填写地址。
面向文档的数据库,凭借其存储无模式数据的能力;也就是说,不符合任何固定模式的数据,比如固定列和固定数据类型,因此是存储这些信息的合适平台。
因此,由于电话日记包含的数据量要小得多,在实践中,我们可以以其他格式存储它,但是当我们处理包含结构化和非结构化信息的大规模数据时,面向文档的数据集的必要性就变得明显起来。
以电话日记为例,数据可以以 JSON 格式存储在面向文档的数据集中,如下所示:
(
{
"name": "John",
"address": "1 Main St.",
"notes": "Met at conference in 2015",
"tel": 2013249978,
},
{
"name": "Jack",
"address": "20 J. Blvd",
"notes": "Gym Instructor",
"tel": 2054584538,
"fax": 3482274573
}
)
JSON,全称JavaScript Object Notation,提供了一种以可移植的基于文本的键值对格式表示数据的方法。如今,JSON 格式的数据在整个行业中无处不在,并已成为存储没有固定模式的数据的标准。它也是一个很好的交换结构化数据的媒介,因此经常用于这样的数据集。
上述示例提供了一个基本的例子,以传达面向文档的数据库是如何工作的。因此,这是一个非常简单且直观的例子。在实践中,像 MongoDB 和 CouchDB 这样的面向文档的数据库被用来存储吉字节和太字节的信息。
例如,考虑一个网站,它存储用户及其电影偏好的数据。每个用户可能有多部他们观看过的电影,评分过的电影,推荐的电影,他们愿望清单中添加的电影,以及其他类似的物品。在这种情况下,数据集中有各种任意的元素,其中许多是可选的,许多可能包含多个值(例如,用户推荐的多部电影),使用 JSON 格式来捕获信息变得最优。这就是面向文档的数据库提供了一个优越和最佳的平台来存储和交换数据的地方。
更具体地说,诸如 MongoDB 之类的数据库以 BSON 格式存储信息,这是 JSON 文档的二进制版本,具有额外的优化以适应数据类型、Unicode 字符和其他功能,以提高基本 JSON 文档的性能。
更全面的一个存储在 MongoDB 中的 JSON 文档的例子可能是关于航空乘客的数据,其中包含了关于个别乘客的许多属性的信息,例如:
{
"_id" : ObjectId("597cdbb193acc5c362e7ae96"),
"firstName" : "Rick",
"age" : 66,
"frequentFlyer" : (
"Delta"
),
"milesEarned" : (
88154
)
}
{
"_id" : ObjectId("597cdbb193acc5c362e7ae97"),
"firstName" : "Nina",
"age" : 53,
"frequentFlyer" : (
"Delta",
"JetBlue",
"Delta"
),
"milesEarned" : (
59226,
62025,
27493
)
}
每个条目都由_id
字段唯一标识,这使我们能够直接查询与特定用户相关的信息,并在不必查询数百万条记录的情况下检索数据。
如今,面向文档的数据库被用来存储各种各样的数据集。例如包括以下用法:
-
日志文件和与日志文件相关的信息
-
文章和其他基于文本的出版物
-
地理位置数据
-
用户/用户账户相关信息
-
许多更适合基于文档/JSON 的存储的用例
知名的面向文档的数据库包括以下内容:
开源 | 商业 |
---|---|
MongoDB | Azure Cosmos DB |
CouchDB | OrientDB |
Couchbase Server | Marklogic |
键值数据库
键值数据库的操作原则是将数据结构化为与键对应的值对。为了突出键值数据库的好处,有必要重新审视哈希映射的重要性,哈希映射是计算机科学中常见的术语,用于指定一种独特的数据结构,为键对提供常数时间查找。
哈希表的一个直观例子如下:
考虑一组 500 本书和五个书架。每个书架有五层。书可以以任意顺序放置,但这将使查找特定书籍变得非常困难,您可能需要在找到所需的书之前浏览数百本书。对书籍进行分类的一种方法是为每个书架分配字母范围,例如 A-E,F-J,K-O,P-T,U-Z,并使用书名的第一个字母将其分配到特定的书架上。然而,假设您有大量以 A-E 字母开头的书。这意味着为 A-E 分配的书架相对于其他书架有更多的书。
一个更优雅的替代方案可能是为每本书分配一个值,并使用相应的值来确定书屋或书架属于哪本书。为了为每本书分配一个数字,我们可以使用书名中每个字母对应的数字之和,分别使用 1-26 的范围来对 A-Z 的字母进行编号:
我们的简单哈希映射
由于我们有五个书架,每个书架有五层,所以我们总共有 25 个书架。将书分配到特定书架的一种方法是取书名中字母的数字值,将其相加并除以 26 得到书的数字值。任何数字除以 25 都会得到 0-25 之间的余数;也就是说,26 个唯一的值。然后我们可以使用这个值来将书分配到特定的书架上。这就成为我们自己创建的哈希函数。
在这 25 个书架中,每个书架现在分配了一个与值 0-25 相对应的数字值,最后一个书架分配了值 24 和 25。例如,书架零被分配用于存储其数字值除以 26 得到零的书籍,书架一被分配用于存储其数字值除以 26 得到一的书籍,书架 25 被分配用于存储其数字值除以 26 得到 24 或 25 的书籍。
一个例子将有助于更具体地说明这个概念。
书名:哈姆雷特
标题的数字值:
哈希值
数字值的总和 = 8 + 1 + 13 + 12 + 5 + 20 = 59
将数字除以 26 = 2,余数为 7
因此,这本书被分配到第七个书架上。
我们基本上找到了一种有条不紊地为每本书分配书架的方法,因为我们有一个固定的规则,所以当新的书籍请求到达时,我们几乎可以立即找到它,因为我们将知道与书籍对应的书架。
上述方法说明了哈希的概念,在实践中,我们将使用一个哈希函数为每本书找到一个唯一的值,假设我们可以获得任意数量的书架和槽,我们可以简单地使用书的纯数值来确定它应该属于哪个书架。
有些情况下,两本书可能具有相同的数值,这种情况下,我们可以将书籍堆叠在相应的槽中。在计算机科学中,多个值对应一个键的这种效果被称为碰撞,在这种情况下,我们将通过列表或类似的数据类型分配多个项目。
在实际应用中,我们要处理的项目比书籍的简单示例要复杂得多。通常,我们会使用更复杂的哈希函数,以降低碰撞的几率,并相应地分配键值对。数据将存储在内存中的连续数组中,因此,当请求某个键时,我们可以通过使用哈希函数来立即找到数据所在的内存位置。
因此,使用键值对存储数据可能非常强大,因为检索与键对应的信息的时间可以非常快,因为无需搜索长列表以识别匹配的键。
键值数据库采用相同的原则为每个记录分配唯一的键,并且与每个键对应的数据存储在相应的位置。在我们讨论 MongoDB 时,我们看到记录被分配了一个特定的键,该键在每个记录中由_id
值标识。在实践中,我们可以使用这个值以恒定时间检索相应的数据。
如前所述,memcached 曾经是存储键值对数据的首选方法,用于需要对频繁使用的数据进行非常快速访问的网络服务。实质上,它作为一个内存缓存,用于存储临时信息。随着 NoSQL 数据库的出现,扩展了 memcached 有限用例的新平台变得突出起来。诸如 Redis 之类的解决方案不仅提供了在内存中存储数据的能力,还提供了将数据持久化到磁盘的能力。此外,这些键值存储支持水平扩展,允许将键值对分布在数百个节点上。
键值存储的缺点是,无法像标准数据库那样灵活地查询数据,后者支持多级索引和更丰富的 SQL 命令集。然而,恒定时间查找的好处意味着对于需要键值结构的用例,几乎没有其他解决方案在性能和效率上可以与之媲美。例如,一个拥有成千上万用户的购物网站可以将用户配置文件信息存储在键值数据库中,并能够通过简单应用与用户 ID 相对应的哈希函数来查找个别信息。
如今,键值数据库使用各种方法来存储数据:
-
SSTables:以字符串形式表示的排序键值对文件(直接映射到Google 文件系统(GFS))。
-
B-树:平衡树,通过遍历叶子/节点来识别值。
-
布隆过滤器:当键的数量很大时使用的更优化的键值方法。它使用多个哈希函数将位值设置为数组中对应的键。
-
分片:涉及将数据分区到多个节点。
众所周知的键值数据库包括:
开源 | 商业 |
---|---|
Redis | 亚马逊 DynamoDB |
Cassandra | Riak |
Aerospike | Oracle NoSQL |
Apache Ignite | Azure Cosmos DB |
Apache Accumulo | Oracle Berkeley DB |
图形数据库
图形数据库提供了一种高效的数据表示,其中记录之间存在相互关系。典型的例子包括您的社交网络好友列表、LinkedIn 联系人、Netflix 电影订阅者。通过利用基于树形/图形数据结构的优化算法进行搜索,图形数据库可以以一种新颖的方式定位信息,相对于其他 NoSQL 解决方案。在这样的结构中,离散信息和属性被表示为叶子、边和节点。
下图显示了一个可以查询的网络的非典型表示,可以使用图形数据库发现或查找复杂的相互关系。在实践中,生产图形数据库包含数百万个节点:
图形数据库
尽管它们不像其他类型的 NoSQL 数据库那样普遍,基于图形的平台被用于业务关键领域。例如,信用卡公司使用图形数据库通过查询数百万数据点来评估其他具有类似购买模式的持卡人的购买行为,以发现个体持卡人可能感兴趣的新产品。社交网络网站使用图形数据库来计算相似度分数,提供好友建议和其他相关指标。
知名的图形数据库包括以下:
开源 | 商业 |
---|---|
Apache Giraph | Datastax Enterprise Graph |
Neo4j | Teradata Aster |
JanusGraph | Oracle Spatial and Graph |
Apache Ignite |
其他 NoSQL 类型和其他类型的数据库
本节描述了当今使用的一些常见 NoSQL 范式。还有一些新兴平台具有自己的优势和独特特点。这里简要概述了其中一些:
类型 | 特性 |
---|---|
面向对象数据库 | 这些数据库利用面向对象编程中的概念来存储以对象表示的数据。 |
云数据库 | 由云供应商提供的数据库,如亚马逊、微软和谷歌,仅在其各自的云平台上提供,如亚马逊 Redshift、Azure SQL 数据库和谷歌 BigQuery。 |
GPU 数据库 | 这是数据库世界中的一个较新的参与者,利用 GPU(图形处理单元)卡来处理数据。例如 MapD、Kinetica 等。 |
FPGA 加速数据库 | 随着英特尔即将宣布发布搭载 FPGA 的新芯片,百度等公司已开始开发利用 FPGA 处理能力来提高 SQL 查询性能的 FPGA 加速系统。 |
流处理/IoT 数据库 | 优化用于处理来自医疗设备和传感器等流数据的数据库,或更一般的平台。其中最流行的一个例子是 Apache Storm。 |
经常被问到的一个问题是是否有一个 NoSQL 数据库适用于所有用例。虽然数据库可以具有支持 NoSQL 系统多个元素的多个特性(通常被称为多模数据库),但在实践中,一个能够在广泛的用例集中表现良好的单一解决方案是罕见的。在实际应用中,公司通常实施多个解决方案来满足数据挖掘需求。在下一节中,我们将使用本章讨论的 NoSQL 解决方案完成一些真实数据集的实际练习。
使用 MongoDB 分析诺贝尔奖获得者的数据
在第一个练习中,我们将使用MongoDB,这是一种领先的面向文档的数据库,来分析 1902 年至今的诺贝尔奖获得者。MongoDB 提供了一个简单直观的界面,用于处理 JSON 文件。正如之前讨论的,JSON 是一种灵活的格式,允许使用结构化方法表示数据。
JSON 格式
考虑以下表:
名字 | 姓氏 | 信息 |
---|---|---|
约翰 | 15 | 主题:历史,等级 B |
杰克 | 18 | 主题:物理,等级 A |
吉尔 | 17 | 主题:物理,等级 A+ |
信息字段包含一个包含在主题和等级下分类的多个值的列。包含多个数据的列也称为包含嵌套数据的列。
可移植性一直是将数据从一个系统转移到另一个系统的重要方面。通常情况下,ODBC 连接器用于在数据库系统之间传输数据。另一种常见的格式是 CSV 文件,其中数据表示为逗号分隔的值。CSV 文件适用于不包含更复杂数据结构(如嵌套值)的结构化数据。在这种情况下,JSON 提供了一种最佳和结构化的方式,使用键值对语法捕获和保留信息。
在 JSON 表示中,表可以定义如下:
(
{
"Firstname":"John",
"Age":15,
"Information":{
"Subject":"History",
"Grade":"B"
}
},
{
"Firstname":"Jack",
"Age":18,
"Information":{
"Subject":"Physics",
"Grade":"A"
}
},
{
"Firstname":"Jill",
"Age":17,
"Information":{
"Subject":"Physics",
"Grade":"A+"
}
}
)
请注意,信息
键包含两个键,主题
和等级
,每个键都有相应的值。
如今,大多数产品开发人员和供应商都能够接受 JSON 格式的数据。此外,由于复杂关系可以以简单的方式在文本格式中表达和交换,JSON 在全球开发者社区中变得非常流行。
MongoDB 以 JSON 格式捕获数据。它在内部以 BSON 的形式存储数据,这是 JSON 数据的优化二进制表示。
安装和使用 MongoDB
MongoDB 支持 Windows、Linux 和 OS X 等所有主要平台。
有关安装 MongoDB 的详细信息可以在官方网站docs.mongodb.com/manual/installation/
上找到。请注意,我们将使用 MongoDB 社区版。
对于我们的练习,我们将重复使用我们的 Cloudera Hadoop 分发 VM 中的 Linux CentOS 环境。
然而,这个练习并不依赖于您安装 MongoDB 的平台。安装完成后,您可以在任何其他支持的平台上执行本章中指示的命令。如果您有一个独立的 Linux 机器,您也可以使用它。
我们将讨论 MongoDB 的一些常见语义,并下载两个数据集来计算按大陆分组的诺贝尔奖获得者数量。诺贝尔奖获得者的完整数据转储可从nobelprize.org获取。数据包含所有获奖者的主要属性。我们希望将这些数据与各国的人口统计信息整合,以提取更有趣的分析信息:
- 下载 MongoDB:MongoDB 可以从
www.mongodb.com/download-center#community
下载。
为了确定适用于我们的版本,我们检查了 CDH VM 上安装的 Linux 版本:
(cloudera@quickstart ~)$ lsb_release -a
LSB Version: :base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch
Distributor ID: CentOS
Description: CentOS release 6.7 (Final)
Release: 6.7
Codename: Final
- 根据信息,我们必须使用 MongoDB 的 CentOS 版本,并根据
docs.mongodb.com/manual/tutorial/install-mongodb-on-red-hat/
上的说明安装软件,如下所示:
The first step involved adding the repo as follows. Type in sudo nano /etc/yum.repos.d/mongodb-org-3.4.repo on the command line and enter the text as shown.
(root@quickstart cloudera)# sudo nano /etc/yum.repos.d/mongodb-org-3.4.repo
### Type in the information shown below and press CTRL-X
### When prompted to save buffer, type in yes
(mongodb-org-3.4)
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.4/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-3.4.asc
以下截图显示了文件的内容:
设置 MongoDB 仓库
如下截图所示,输入Y
表示是:
保存.repo 文件
按照图像所示保存文件如下。这将允许我们安装mongo-db
:
编写和保存.repo 文件
# Back in terminal, type in the following
(cloudera@quickstart ~)$ sudo yum install -y mongodb-org
(...)
Installing:
mongodb-org x86_64 3.4.6-1.el6 mongodb-org-3.4 5.8 k
Installing for dependencies:
mongodb-org-mongos x86_64 3.4.6-1.el6 mongodb-org-3.4 12 M
mongodb-org-server x86_64 3.4.6-1.el6 mongodb-org-3.4 20 M
mongodb-org-shell x86_64 3.4.6-1.el6 mongodb-org-3.4 11 M
mongodb-org-tools x86_64 3.4.6-1.el6 mongodb-org-3.4 49 M
Transaction Summary
=====================================================================
Install 5 Package(s)
Total download size: 91 M
Installed size: 258 M
Downloading Packages:
(1/5): mongodb-org-3.4.6-1.el6.x86_64.rpm | 5.8 kB 00:00
(...)
Installed:
mongodb-org.x86_64 0:3.4.6-1.el6
Dependency Installed:
mongodb-org-mongos.x86_64 0:3.4.6-1.el6 mongodb-org-server.x86_64 0:3.4.6-1.el6
mongodb-org-shell.x86_64 0:3.4.6-1.el6 mongodb-org-tools.x86_64 0:3.4.6-1.el6
Complete!
### Attempting to start mongo without first starting the daemon will produce an error message ###
### You need to start the mongo daemon before you can use it ###
(cloudera@quickstart ~)$ mongo MongoDB shell version v3.4.6
connecting to: mongodb://127.0.0.1:27017
2017-07-30T10:50:58.708-0700 W NETWORK (thread1) Failed to connect to 127.0.0.1:27017, in(checking socket for error after poll), reason: Connection refused
2017-07-30T10:50:58.708-0700 E QUERY (thread1) Error: couldn't connect to server 127.0.0.1:27017, connection attempt failed :
connect@src/mongo/shell/mongo.js:237:13
@(connect):1:6
exception: connect failed
### The first step is to create the MongoDB dbpath - this is where MongoDB will store all data
### Create a folder called, mongodata, this will be the mongo dbpath ###
(cloudera@quickstart ~)$ mkdir mongodata
### Start mongod ###
(cloudera@quickstart ~)$ mongod --dbpath mongodata
2017-07-30T10:52:17.200-0700 I CONTROL (initandlisten) MongoDB starting : pid=16093 port=27017 dbpath=mongodata 64-bit host=quickstart.cloudera
(...)
2017-07-30T10:52:17.321-0700 I INDEX (initandlisten) build index done. scanned 0 total records. 0 secs
2017-07-30T10:52:17.321-0700 I COMMAND (initandlisten) setting featureCompatibilityVersion to 3.4
2017-07-30T10:52:17.321-0700 I NETWORK (thread1) waiting for connections on port 27017
打开一个新的终端,并按照以下截图中所示下载 JSON 数据文件:
从 Mac OS X 的终端应用程序中选择“打开终端”
# Download Files
# laureates.json and country.json ###
# Change directory to go to the mongodata folder that you created earlier
(cloudera@quickstart ~)$ cd mongodata
(cloudera@quickstart mongodata)$ curl -o laureates.json "http://api.nobelprize.org/v1/laureate.json"
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 428k 0 428k 0 0 292k 0 --:--:-- 0:00:01 --:--:-- 354k
### Clean the file laureates.json
### Delete content upto the first ( on the first line of the file
### Delete the last } character from the file
### Store the cleansed dataset in a file called laureates.json
请注意,文件需要稍作修改。代码如下图所示:
修改我们应用程序的.json 文件
(cloudera@quickstart mongodata)$ cat laureates.json | sed 's/^{"laureates"://g' | sed 's/}$//g' > mongofile.json
### Import the file laureates.json into MongoDB
### mongoimport is a utility that is used to import data into MongoDB
### The command below will import data from the file, mongofile.json
### Into a db named nobel into a collection (i.e., a table) called laureates
(cloudera@quickstart mongodata)$ mongoimport --jsonArray --db nobel --collection laureates --file mongofile.json 2017-07-30T11:06:35.228-0700 connected to: localhost
2017-07-30T11:06:35.295-0700 imported 910 documents
为了将laureate.json
中的数据与特定国家的信息相结合,我们需要从geonames.org下载countryInfo.txt
。我们现在将下载练习所需的第二个文件country.json
。我们将使用laureates.json
和country.json
进行练习。
### country.json
:从www.geonames.org
下载(许可证:creativecommons.org/licenses/by/3.0/
)。修改 JSON 字符串的开头和结尾,以便导入 MongoDB,如下所示:
# The file country.json contains descriptive information about all countries
# We will use this file for our tutorial
### Download country.json
(cloudera@quickstart mongodata)$ curl -o country.json "https://raw.githubusercontent.com/xbsd/packtbigdata/master/country.json"
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 113k 100 113k 0 0 360k 0 --:--:-- --:--:-- --:--:-- 885k
### The file, country.json has already been cleaned and can be imported directly into MongoDB
(cloudera@quickstart mongodata)$ mongoimport --jsonArray --db nobel --collection country --file country.json 2017-07-30T12:10:35.554-0700 connected to: localhost
2017-07-30T12:10:35.580-0700 imported 250 documents
### MONGO SHELL ###
(cloudera@quickstart mongodata)$ mongo MongoDB shell version v3.4.6
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.6
Server has startup warnings:
(...)
2017-07-30T10:52:17.298-0700 I CONTROL (initandlisten)
### Switch to the database nobel using the 'use <databasename>' command
> use nobel switched to db nobel
### Show all collections (i.e., tables)
### This will show the tables that we imported into MongoDB - country and laureates
> show collections country
laureates
>
### Collections in MongoDB are the equivalent to tables in SQL
### 1\. Common Operations
### View collection statistics using db.<dbname>.stats()
> db.laureates.stats()
"ns" : "nobel.laureates", # Name Space
"size" : 484053, # Size in Bytes
"count" : 910, # Number of Records
"avgObjSize" : 531, # Average Object Size
"storageSize" : 225280, # Data size
# Check space used (in bytes)
> db.laureates.storageSize() 225280
# Check number of records
> db.laureates.count() 910
### 2\. View data from collection
###
### There is an extensive list of commands that can be used in MongoDB. As such discussing them all is outside the scope of the text. However, a few of the familiar commands have been given below as a marker to help the reader get started with the platform.
### See first record for laureates using findOne()
### findOne() will show the first record in the collection
> db.laureates.findOne()
{
"_id" : ObjectId("597e202bcd8724f48de485d4"),
"id" : "1",
"firstname" : "Wilhelm Conrad",
"surname" : "Röntgen",
"born" : "1845-03-27",
"died" : "1923-02-10",
"bornCountry" : "Prussia (now Germany)",
"bornCountryCode" : "DE",
"bornCity" : "Lennep (now Remscheid)",
"diedCountry" : "Germany",
"diedCountryCode" : "DE",
"diedCity" : "Munich",
"gender" : "male",
"prizes" : (
{
"year" : "1901",
"category" : "physics",
"share" : "1",
"motivation" : "\"in recognition of the extraordinary services he has rendered by the discovery of the remarkable rays subsequently named after him\"",
"affiliations" : (
{
"name" : "Munich University",
"city" : "Munich",
"country" : "Germany"
}
)
}
)
}
### See all records for laureates
> db.laureates.find()
{ "_id" : ObjectId("597e202bcd8724f48de485d4"), "id" : "1", "firstname" : "Wilhelm Conrad", "surname" : "Röntgen", "born" : "1845-03-27", "died" : "1923-02-10", "bornCountry" : "Prussia (now Germany)", "bornCountryCode" : "DE", "bornCity" : "Lennep (now Remscheid)"
(...)
...
### MongoDB functions accept JSON formatted strings as parameters to options
### Some examples are shown below for reference
### Query a field - Find all Nobel Laureates who were male
> db.laureates.find({"gender":"male"})
(...)
{ "_id" : ObjectId("597e202bcd8724f48de485d5"), "id" : "2", "firstname" : "Hendrik Antoon", "surname" : "Lorentz", "born" : "1853-07-18", "died" : "1928-02-04", "bornCountry" : "the Netherlands", "bornCountryCode" : "NL", "bornCity" : "Arnhem", "diedCountry" : "the Netherlands", "diedCountryCode" : "NL", "gender" : "male", "prizes" : ( { "year" : "1902", "category" : "physics", "share" : "2", "motivation" : "\"in recognition of the extraordinary service they rendered by their researches into the influence of magnetism upon radiation phenomena\"", "affiliations" : ( { "name" : "Leiden University", "city" : "Leiden", "country" : "the Netherlands" } ) } ) }
(...)
查询一个字段 - 查找所有在美国出生并获得诺贝尔物理学奖的诺贝尔奖获得者。请注意,这里有一个嵌套字段(如所示,类别在奖项下)。因此,我们将使用点表示法,如下图所示。
说明category
,一个嵌套字段的图像:
嵌套的 JSON 字段
> db.laureates.find({"bornCountryCode":"US", "prizes.category":"physics", "bornCity": /Chicago/})
{ "_id" : ObjectId("597e202bcd8724f48de48638"), "id" : "103", "firstname" : "Ben Roy", "surname" : "Mottelson", "born" : "1926-07-09", "died" : "0000-00-00", "bornCountry" : "USA", "bornCountryCode" : "US", "bornCity" : "Chicago, IL",
...
### Check number of distinct prize categories using distinct
> db.laureates.distinct("prizes.category") (
"physics",
"chemistry",
"peace",
"medicine",
"literature",
"economics"
)
### Using Comparison Operators
### MongoDB allows users to chain multiple comparison operators
### Details on MongoDB operators can be found at: https://docs.mongodb.com/manual/reference/operator/
# Find Nobel Laureates born in either India or Egypt using the $in operator
> db.laureates.find ( { bornCountryCode: { $in: ("IN","EG") } } )
{ "_id" : ObjectId("597e202bcd8724f48de485f7"), "id" : "37", "firstname" : "Sir Chandrasekhara Venkata", "surname" : "Raman", "born" : "1888-11-07", "died" : "1970-11-21", "bornCountry" : "India", "bornCountryCode" : "IN", "bornCity" : "Tiruchirappalli", "diedCountry" : "India", "diedCountryCode" : "IN", "diedCity" : "Bangalore", "gender" : "male", "prizes" : ( { "year" : "1930", "category" : "physics", "share" : "1", "motivation" : "\"for his work on the scattering of light and for the discovery of the effect named after him\"", "affiliations" : ( { "name" : "Calcutta University", "city" : "Calcutta", "country" : "India" } ) } ) }
...
### Using Multiple Comparison Operators
### Find Nobel laureates who were born in either US or China and won prize in either Physics or Chemistry using the $and and $or operator
> db.laureates.find( {
$and : ({ $or : ( { bornCountryCode : "US" }, { bornCountryCode : "CN" } ) },
{ $or : ( { "prizes.category" : "physics" }, { "prizes.category" : "chemistry" } ) }
)
} )
{ "_id" : ObjectId("597e202bcd8724f48de485ee"), "id" : "28", "firstname" : "Robert Andrews", "surname" : "Millikan", "born" : "1868-03-22", "died" : "1953-12-19", "bornCountry" : "USA", "bornCountryCode" : "US", "bornCity" : "Morrison, IL", "diedCountry" : "USA", "diedCountryCode" : "US", "diedCity" : "San Marino, CA", "gender" : "male", "prizes" : ( { "year" : "1923", "category" : "physics", "share" : "1", "motivation" : "\"for his work on the elementary charge of electricity and on the photoelectric effect\"", "affiliations" : ( { "name" : "California Institute of Technology (Caltech)", "city" : "Pasadena, CA", "country" : "USA" } ) } ) }
...
### Performing Aggregations is one of the common operations in MongoDB queries
### MongoDB allows users to perform pipeline aggregations, map-reduce aggregations and single purpose aggregations
### Details on MongoDB aggregations can be found at the URL
### https://docs.mongodb.com/manual/aggregation/
### Aggregation Examples
### Count and aggregate total Nobel laureates by year and sort in descending order
### Step 1: Use the $group operator to indicate that prize.year will be the grouping variable
### Step 2: Use the $sum operator (accumulator) to sum each entry under a variable called totalPrizes
### Step 3: Use the $sort operator to rank totalPrizes
> db.laureates.aggregate(
{$group: {_id: '$prizes.year', totalPrizes: {$sum: 1}}},
{$sort: {totalPrizes: -1}}
);
{ "_id" : ( "2001" ), "totalPrizes" : 15 }
{ "_id" : ( "2014" ), "totalPrizes" : 13 }
{ "_id" : ( "2002" ), "totalPrizes" : 13 }
{ "_id" : ( "2000" ), "totalPrizes" : 13 }
(...)
### To count and aggregate total prizes by country of birth
> db.laureates.aggregate(
{$group: {_id: '$bornCountry', totalPrizes: {$sum: 1}}},
{$sort: {totalPrizes: -1}}
);
{ "_id" : "USA", "totalPrizes" : 257 }
{ "_id" : "United Kingdom", "totalPrizes" : 84 }
{ "_id" : "Germany", "totalPrizes" : 61 }
{ "_id" : "France", "totalPrizes" : 51 }
...
### MongoDB also supports PCRE (Perl-Compatible) Regular Expressions
### For more information, see https://docs.mongodb.com/manual/reference/operator/query/regex
### Using Regular Expressions: Find count of nobel laureates by country of birth whose prize was related to 'radiation' (as indicated in the field motivation under prizes)
> db.laureates.aggregate(
{$match : { "prizes.motivation" : /radiation/ }},
{$group: {_id: '$bornCountry', totalPrizes: {$sum: 1}}},
{$sort: {totalPrizes: -1}}
);
{ "_id" : "USA", "totalPrizes" : 4 }
{ "_id" : "Germany", "totalPrizes" : 2 }
{ "_id" : "the Netherlands", "totalPrizes" : 2 }
{ "_id" : "United Kingdom", "totalPrizes" : 2 }
{ "_id" : "France", "totalPrizes" : 1 }
{ "_id" : "Prussia (now Russia)", "totalPrizes" : 1 }
#### Result: We see that the highest number of prizes (in which radiation was mentioned as a key-word) was the US
### Interestingly, we can also do joins and other similar operations that allow us to combine the data with other data sources
### In this case, we'd like to join the data in laureates with the data from country information obtained earlier
### The collection country contains many interesting fields, but for this exercise, we will show how to find the total number of nobel laureates by continent
### The Left Join
### Step 1: Use the $lookup operator to define the from/to fields, collection names and assign the data to a field named countryInfo
### We can join the field bornCountryCode from laureates with the field countryCode from the collection country
> db.laureates.aggregate(
{$lookup: { from: "country", localField: "bornCountryCode", foreignField: "countryCode", as: "countryInfo" }})
{ "_id" : ObjectId("597e202bcd8724f48de485d4"), "id" : "1", "firstname" : "Wilhelm Conrad", "surname" : "Röntgen", "born" : "1845-03-27", "died" : "1923-02-10", "bornCountry" : "Prussia (now Germany)", "bornCountryCode" : "DE", "bornCity" : "Lennep (now (..) "country" : "Germany" } ) } ), "countryInfo" : ( { "_id" : ObjectId("597e2f2bcd8724f48de489aa"), "continent" : "EU", "capital" : "Berlin", "languages" : "de", "geonameId" : 2921044, "south" : 47.2701236047002, ...
### With the data joined, we can now perform combined aggregations
### Find the number of Nobel laureates by continent
> db.laureates.aggregate(
{$lookup: { from: "country", localField: "bornCountryCode", foreignField: "countryCode", as: "countryInfo" }},
{$group: {_id: '$countryInfo.continent', totalPrizes: {$sum: 1}}},
{$sort: {totalPrizes: -1}}
);
... );
{ "_id" : ( "EU" ), "totalPrizes" : 478 }
{ "_id" : ( "NA" ), "totalPrizes" : 285 }
{ "_id" : ( "AS" ), "totalPrizes" : 67 }
...
This indicates that Europe has by far the highest number of Nobel Laureates.
还有许多其他操作可以执行,但前一节的目的是以简单的用例高层次介绍 MongoDB。本章中提供的 URL 包含有关使用 MongoDB 的更深入信息。
行业中还有几种可视化工具用于与 MongoDB 集合中存储的数据进行交互和可视化,使用点对点界面。一个简单但功能强大的工具叫做 MongoDB Compass,可以在www.mongodb.com/download-center?filter=enterprise?jmp=nav#compass.
下载。
导航到前面提到的 URL,并下载适合您环境的 Compass 版本:
下载 MongoDB Compass
安装后,您将看到欢迎屏幕。点击“下一步”直到看到主仪表板:
MongoDB Compass 截图
点击“性能”以查看 MongoDB 的当前状态:
MongoDB 性能屏幕
单击左侧边栏上单词旁边的箭头,扩展诺贝尔数据库。您可以单击并拖动条形图的不同部分,并运行临时查询。如果您想要对数据集有一个整体的了解,而不必手动运行所有查询,这非常有用,如下图所示:
在 MongoDB Compass 中查看我们的文件
使用真实世界数据跟踪医生的付款
医生和医院都会收到来自各种外部组织的付款,例如从从事销售代表的制药公司,这些代表不仅教育从业者使用他们的产品,还提供礼物或以其他方式提供支付。理论上,给医生的礼物或付款并不意味着要影响他们的处方行为,制药公司采取谨慎措施来对向医疗保健提供者支付的款项进行核查和平衡。
2010 年,奥巴马总统的标志性平价医疗法案(ACA),在民间俗称为奥巴马医改,生效。与 ACA 同时生效的是一项名为阳光法案的单独立法,该法案规定了制药公司和其他组织必须报告以货币价值(直接或间接)支付的物品。尽管过去存在这样的规定,但很少有这样的规定可以公开获取。通过公开提供向所有医生支付的详细付款记录,阳光法案在涉及医疗保健提供者的货币交易中引入了前所未有的透明度。
数据可以在 CMS Open Payments 的网站openpaymentsdata.cms.gov
上免费获取。
该网站提供了一个查询数据的接口,但没有任何手段进行大规模数据聚合。例如,如果用户想要找到康涅狄克州的总付款金额,通过默认的基于 Web 的工具运行查询没有简单和容易的方法。提供了提供此功能的 API,但需要一定的熟悉度和技术知识才能有效使用。有第三方产品提供这样的设施,但在大多数情况下它们是昂贵的,并且最终用户无法根据自己的特定需求修改软件。
在本教程中,我们将开发一个快速、高效的基于 Web 的应用程序,用于分析 2016 年向医生支付的数千万条记录。我们将使用 NoSQL 数据库、R 和 RStudio 的组合来创建最终产品 - 基于 Web 的门户,通过该门户最终用户可以实时查询数据库。
我们将使用以下技术来开发应用程序:
-
Kdb+ NoSQL 数据库:
www.kx.com
-
R
-
RStudio
对于本教程,我将使用我们为 Hadoop 练习下载的 VM 镜像。这些工具也可以安装在 Windows、Mac 和其他 Linux 机器上。选择 VM 主要是为了提供一个一致的、本地的、与操作系统无关的平台。
安装 kdb+、R 和 RStudio
提供了 Packt Data Science VM 下载,其中包含本章所需的所有必要软件。但是,如果您更喜欢在本地计算机上安装软件,可以在以下部分提供的说明中进行。您可以跳过安装部分,直接进入开发开放支付应用程序部分。
安装 kdb+
**kdb+**是一个时间序列、内存中的列式数据库,已经在金融行业使用了近 20 年。它是可用于进行大规模数据挖掘的最快数据库平台之一,但由于几乎一直被对冲基金和投资银行专门使用,因此并不像其他 NoSQL 工具那样为人所知。特别是由于其速度和在处理大量数据时的低开销,它被进行高频交易的算法交易台使用。
使用 kdb+,在笔记本电脑上分析数千万甚至数亿条记录相当简单。主要的约束将在硬件层面 - 例如可用于处理数据的内存、磁盘空间和 CPU 的数量。在本教程中,我们将安装可供非商业使用的免费 32 位版本的 kdb+。
kdb+不是开源的,但学术机构可以通过写信至academic@kx.com
免费使用 64 位许可证。
kdb+具有某些关键特征,使其非常适合大规模数据分析:
-
低级实现:数据库是用 C 编写的,因此减少了大多数当代 NoSQL 数据库的性能问题,这些数据库严重依赖于 Java,后者实现了多层抽象以提供处理能力。
-
架构简单:kdb+数据库的整个二进制文件大小约为 500-600 KB。这只是 MP3 歌曲大小的一小部分,即使在拨号连接上也可以轻松下载
-
MapReduce:该数据库实现了一个内部 MapReduce 过程,允许查询同时在多个核心上执行
-
无需安装:该数据库不需要系统级别的特权,用户可以在大多数系统上使用他们的用户帐户开始使用 kdb+
-
企业就绪:该数据库已经使用了近 20 年,是一个非常成熟的产品,用于全球企业环境中分析高频交易数据等应用
-
接口广泛可用:该数据库具有广泛的接口,可用于诸如 C、C++、C#、Java、R、Python、MATLAB 等语言,以便与现有软件轻松集成
安装 kdb+的步骤如下。请注意,如果您使用 Packt 数据科学 VM,则无需进行额外安装。这些说明主要是为了那些想要全新安装软件的用户提供的。
尽管说明是针对 Linux 的,但对于 Windows 和 Mac 来说,安装过程也非常简单。这些说明主要是针对 Packt 数据科学 VM 的。有关下载 Packt 数据科学 VM 的说明,请参阅第三章,分析工具包
- 访问www.kx.com,并从“Connect with us”菜单中点击Download下拉选项。您也可以直接访问位于
kx.com/download/
的下载页面:
Kx Systems 首页
下载页面如下截图所示:
下载 KDB+
-
在下一页上点击下载。
-
点击
kx.com/download/
,同意条款后,您可以选择您需要的下载。如果您使用 VM,请下载Linux-86 版本。 -
选择“保存文件”以将下载的 ZIP 文件保存在您的下载文件夹中:
KDB+ 32 位许可条款
转到下载文件所在的文件夹,并将 ZIP 文件复制到您的主目录下:
KDB+ Zip 文件下载
对于 Mac 或 Linux 系统,这将是~/
文件夹。在 Windows 中,将 ZIP 文件复制到C:\
并解压以提取q
文件夹。以下说明主要适用于基于 Linux 的系统:
$ cd Downloads/ # cd to the folder where you have downloaded the zip file
$ unzip linuxx86.zip
Archive: linuxx86.zip
inflating: q/README.txt
inflating: q/l32/q
inflating: q/q.q
inflating: q/q.k
inflating: q/s.k
inflating: q/trade.q
inflating: q/sp.q
$ mv ~/Downloads/q ~/
$ cd ~/q
$ cd l32
$ ./q KDB+ 3.5 2017.06.15 Copyright (C) 1993-2017 Kx Systems
l32/ 1()core 3830MB cloudera quickstart.cloudera 10.0.2.15 NONEXPIRE
Welcome to kdb+ 32bit edition
For support please see http://groups.google.com/d/forum/personal-kdbplus
Tutorials can be found at http://code.kx.com/wiki/Tutorials
To exit, type \\
To remove this startup msg, edit q.q
q)\\
/NOTE THAT YOU MAY NEED TO INSTALL THE FOLLOWING IF YOU GET AN ERROR MESSAGE STATING THAT THE FILE q CANNOT BE FOUND. IN THAT CASE, INSTALL THE REQUISITE SOFTWARE AS SHOWN BELOW
$ sudo dpkg --add-architecture i386
$ sudo apt-get update
$ sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386
安装 R
应用的前端将使用 R 开发。有三种选项可供安装 R 以完成本教程:
-
如果您已经从第三章,分析工具包中安装了 Microsoft R,并且将在本教程中使用您的本地机器,则无需进行进一步安装。
-
或者,如果您将使用 Packt 数据科学 Virtualbox VM,则无需进行进一步安装。
-
如果您计划从官方 R 网站安装 R,则可以从列在
cran.r-project.org/mirrors.html
的下载站点(镜像)中下载二进制文件:
安装开源 R
安装 RStudio
我们将使用 RStudio 来构建我们的基于 Web 的应用程序。您可以从网站上下载 RStudio 的二进制文件,也可以从终端安装。RStudio 有两个版本-RStudio 桌面版和 RStudio 服务器版。这两个版本都可以用于构建应用程序。服务器版提供了一个可以供多个用户使用的界面,而桌面版通常在用户的本地机器上使用。
这些说明也出现在第三章,分析工具包中。它们已在此提供供参考。
有两种方法可以完成 R 教程的安装:
-
如果您将使用 Packt 数据科学 VM,则无需进行进一步安装。
-
如果您将在本教程中使用本地计算机,您可以从
www.rstudio.com/products/rstudio/download/#download
下载 RStudio 桌面,或者从www.rstudio.com/products/rstudio/download-server/
下载 RStudio 服务器(仅适用于 Linux 用户)。
以下说明是为希望从供应商网站下载 RStudio 并进行全新安装的用户提供的:
转到www.rstudio.com
的网站,然后点击产品 | RStudio:
开源 R Studio 桌面版本
在 RStudio 页面上,点击下载 RStudio 桌面:
选择 RStudio 桌面
选择 RStudio 桌面的免费版本:
选择开源 R Studio 桌面
RStudio 适用于 Windows、Mac 和 Linux。
下载适合您系统的可执行文件,然后进行安装:
RStudio 二进制文件(版本)
CMS Open Payments 门户
在这一部分,我们将开始为 CMS Open Payments 开发我们的应用程序。
Packt 数据科学 VM 包含本教程所需的所有软件。要下载 VM,请参考第三章,分析工具包。
下载 CMS Open Payments 数据
CMS Open Payments 数据可以直接从 CMS 网站作为基于 Web 的下载获得。我们将使用 Unix wget 实用程序下载数据,但首先我们必须在 CMS 网站上注册,以获得我们自己的 API 密钥:
- 转到
openpaymentsdata.cms.gov
,然后点击页面右上角的登录链接:
CMS OpenPayments 的主页
点击注册:
CMS OpenPayments 的注册页面
输入您的信息,然后点击创建我的帐户按钮:
CMS OpenPayments 的注册表格
登录到您的帐户:
登录到 CMS OpenPayments
点击管理下的Packt 开发者应用程序。请注意,这里的“应用程序”是指您可能创建的应用程序,该应用程序将查询 CMS 网站上可用的数据:
创建“应用程序”
为应用程序指定一个名称(示例显示在下图中):
定义一个应用程序
您将收到通知,应用程序令牌已创建:
创建应用程序令牌
系统将生成一个应用程序令牌。复制应用程序令牌:
应用程序令牌
- 现在,以 packt 用户的身份登录到 Packt 数据科学 VM,并在用您被分配的术语
YOURAPPTOKEN
替换为以下 shell 命令后执行(它将是一长串字符/数字)。请注意,对于本教程,我们将仅下载一些列并将数据限制为仅医生(另一个选项是医院)。
您可以通过减少命令末尾指定的限制值来减少下载的数据量。在命令中,我们使用了12000000
(1200 万),这将允许我们下载代表医生支付的整个 2016 年数据集。例如,如果您只下载了一百万条记录,而不是大约 1100 万到 1200 万条记录,应用程序仍将正常工作。
注意:下面显示了两种方法。一种使用令牌,另一种不使用令牌。应用程序令牌允许用户具有更高的限流限制。更多信息请参阅dev.socrata.com/docs/app-tokens.html
# Replace YOURAPPTOKEN and 12000000 with your API Key and desired record limit respectively
cd /home/packt;
time wget -O cms2016.csv 'https://openpaymentsdata.cms.gov/resource/vq63-hu5i.csv?$$app_token=YOURAPPTOKEN&$query=select Physician_First_Name as firstName,Physician_Last_Name as lastName,Recipient_City as city,Recipient_State as state,Submitting_Applicable_Manufacturer_or_Applicable_GPO_Name as company,Total_Amount_of_Payment_USDollars as payment,Date_of_Payment as date,Nature_of_Payment_or_Transfer_of_Value as paymentNature,Product_Category_or_Therapeutic_Area_1 as category,Name_of_Drug_or_Biological_or_Device_or_Medical_Supply_1 as product where covered_recipient_type like "Covered Recipient Physician" limit 12000000'
重要提示:也可以在不使用应用程序令牌的情况下下载文件。但是,应该谨慎使用该方法。可以在以下显示的 URL 中下载文件,而无需使用应用程序令牌:
# Downloading without using APP TOKEN
wget -O cms2016.csv 'https://openpaymentsdata.cms.gov/resource/vq63-hu5i.csv?$query=select Physician_First_Name as firstName,Physician_Last_Name as lastName,Recipient_City as city,Recipient_State as state,Submitting_Applicable_Manufacturer_or_Applicable_GPO_Name as company,Total_Amount_of_Payment_USDollars as payment,Date_of_Payment as date,Nature_of_Payment_or_Transfer_of_Value as paymentNature,Product_Category_or_Therapeutic_Area_1 as category,Name_of_Drug_or_Biological_or_Device_or_Medical_Supply_1 as product where covered_recipient_type like "Covered Recipient Physician" limit 12000000'
创建 Q 应用程序
本节描述了创建 kdb+/Q 应用程序的过程,从数据库加载数据并创建将作为应用程序后端的脚本开始。
加载数据
使用 ID packt
(密码:packt
)登录 VM:
登录 Packt VM
# We will start KDB+ - the NoSQL database that we'll use for the tutorial
# Launch the Q Console by typing:
packt@vagrant:~$ rlwrap ~/q/l32/q -s 4 -p 5001
KDB+ 3.5 2017.06.15 Copyright (C) 1993-2017 Kx Systems
l32/ 1()core 3951MB packt vagrant 127.0.1.1 NONEXPIRE
Welcome to kdb+ 32bit edition
For support please see http://groups.google.com/d/forum/personal-kdbplus
Tutorials can be found at http://code.kx.com/wiki/Tutorials
To exit, type \\
To remove this startup msg, edit q.q
q)
# Enter the following at the Q console. Explanations for each of the commands have been provided in the comments (using /):/change to the home directory for user packt
\cd /home/packt/ /Define the schema of the cms table
d:(`category`city`company`date`firstName`lastName`payment`paymentNature`product`state)!"SSSZSSFSSS"; /Read the headersfrom the cms csv file. These will be our table column names
columns:system "head -1 cms2016.csv";
columns:`$"," vs ssr(raze columns;"\"";""); /Run Garbage Collection
.Q.gc(); /Load the cms csv file
\ts cms2016:(d columns;enlist",")0:`:cms2016.csv; /Add a month column to the data
\ts cms2016: `month`date xasc update month:`month$date, date:`date$date from cms2016
.Q.gc(); /Modify character columns to be lower case. The data contains u
\ts update lower firstName from `cms2016
\ts update lower lastName from `cms2016
\ts update lower city from `cms2016
\ts update lower state from `cms2016
\ts update lower product from `cms2016
\ts update lower category from `cms2016
\ts update lower paymentNature from `cms2016
\ts update lower company from `cms2016
.Q.gc()
cms2016:`month`date`firstName`lastName`company`state`city`product`category`payment`paymentNature xcols cms2016
count cms2016 /11 million /Function to save the data that was read from the CMS csv file
savedata:{show (string .z.T)," Writing: ",string x;cms::delete month from select from cms2016 where month=x; .Q.dpft(`:cms;x;`date;`cms)}
/Save the data in monthly partitions in the current folder
savedata each 2016.01m +til 12
后端代码
脚本完成后,通过键入\\
并按Enter退出 Q 提示。
将以下文本复制到名为cms.q
的文件中:
system "p 5001"
system "l /home/packt/cms"
/firstCap: Takes a string (sym) input and capitalizes the first letter of each word separated by a blank space
firstCap:{" " sv {@(x;0;upper)} each (" " vs string x) except enlist ""}
/VARIABLES AND HELPER TABLES
/alldata: Aggregates data from the primary cms database
alldata: distinct `company`product xasc update showCompany:`$firstCap each company, showProduct:`$firstCap each product from ungroup select distinct product by company from cms where not null product
/minDate: First month
minDate:exec date from select min date from cms where month=min month
/maxDate: Last month
maxDate:exec date from select max date from cms where month=max month
/companyStateCity: Cleans and normalises the company names (capitalisations, etc)
companyStateCity:select asc upper distinct state, asc `$firstCap each distinct city by company from cms
/FUNCTIONS
/getShowProduct: Function to get product list from company name getShowProduct:{$((`$"Select All") in x;raze exec showProduct from alldata;exec showProduct from alldata where showCompany in x)}
/getShowState: Function to get state list from company name getShowState:{$((`$"Select All") in x;raze exec state from companyStateCity;exec state from companyStateCity where company = exec first company from alldata where showCompany in x)}
/getShowCity: Function to get city list from company name
getShowCity:{$((`$"Select All") in x;raze exec city from companyStateCity;exec city from companyStateCity where company = exec first company from alldata where showCompany in x)}
/getShowInfo: Generic Function for Product, State and City
getShowInfo:{y:`$"|" vs y;:asc distinct raze raze $(x~`product;getShowProduct each y;x~`state;getShowState each y;x~`city;getShowCity each y;"")}
/Example: Run this after loading the entire script after removing the comment mark (/) from the beginning
/getShowInfo(`state;"Abb Con-cise Optical Group Llc|Select All|Abbott Laboratories")
/Convert encoded URL into a Q dictionary
decodeJSON:{.j.k .h.uh x}
/Convert atoms to list
ensym:{$(0>type x;enlist x;x)}
/Date functions
withinDates:{enlist (within;`date;"D"$x(`date))}
withinMonths:{enlist (within;`month;`month$"D"$x(`date))}
/Helper function to remove null keys
delNullDict:{kx!x kx:where {not x~0n} each x}
/If showdata=enlist 1,
/Function to process the data for displaying results only
getData:{"x is the dictionary from web";d:`$dx:lower delNullDict x; enz:`$delete showData,date,columns from dx; ?(`cms;(withinMonths x),(withinDates x),{(in;x 0;enlist 1_x)} each ((key enz),'value enz);0b;(dc)!dc:ensym `$x`columns)}
/Aggregation Function
aggDict:(`$("Total Payment";"Number of Payments";"Minimum Payment";"Maximum Payment";"Average Payment"))!((sum;`payment);(#:;`i);(min;`payment);(max;`payment);(avg;`payment))
/Function to aggregate the data
getDataGroups:{(aggDict;x) "x is the dictionary from web";d:`$dx:lower delNullDict x; enz:`$delete showData,date,columns,aggVars,aggData from dx; ?(`cms;(withinMonths x),(withinDates x),{(in;x 0;enlist 1_x)} each ((key enz),'value enz);xv!xv:ensym `$x`aggVars;xa!aggDict xa:ensym `$x`aggData)}(aggDict;)
/Generic Function to create error messages
errtable:{tab:(()Time:enlist `$string .z.Z;Alert:enlist x);(tab;"Missing Fields")}
/Validation for input
initialValidation:{$(0n~x(`company);:errtable `$"Company must be selected";(`aggVars in key x) and ((0=count x(`aggVars)) or 0n~x(`aggData));:errtable `$"Both Metric and Aggregate Data field should be selected when using Aggregate Data option";x)}
/Special Handling for some variables, in this case month specialHandling:{0N!x;$(`month in cols x; update `$string month from x;x)}
/Normalise Columns
columnFix:{(`$firstCap each cols x) xcol x}
/Use comma separator for numeric values
commaFmt: {((x<0)#"-"),(reverse","sv 3 cut reverse string floor a),1_string(a:abs x)mod 1}
/Wrapper for show data and aggregate data options
getRes:{0N!x;.Q.gc();st:.z.t;x:decodeJSON x; if (not x ~ ix:initialValidation x;:ix); res:$(`aggData in key x;getDataGroups x;getData x);res:specialHandling res; res:columnFix res;ccms:count cms; cres:count res; en:.z.t; .Q.gc();:(res;`$(string en),": Processed ",(commaFmt ccms)," records in ",(string en - st)," seconds. Returned result with ",(commaFmt cres)," rows.\n")
创建前端 Web 门户
R Shiny是一个旨在简化基于 Web 的应用程序开发的软件包,自 2012-2013 年左右推出以来一直备受关注。一般来说,R 开发人员往往不太擅长前端开发,因为他们的主要工作领域与统计学或类似学科相关。
随着数据科学作为一种职业和主流活动的普及,创建复杂的基于 Web 的应用程序成为必要手段,以便在动态环境中向最终用户提供结果。
自 2010-2011 年以来,JavaScript 几乎失去了原有的吸引力,却又意外地卷土重来,很快,Web 世界就因发布各种领先的 JavaScript 软件包(如 D3、Angular、Ember 等)而沸腾起来。
但这些主要是由经验丰富的 JavaScript 开发人员使用的,其中很少有人也精通 R。开发一个解决方案,可以帮助弥合 JavaScript 基础应用程序开发和 R 编程之间的差距,成为 R 开发人员展示和与更广泛的受众分享他们的工作的必要性。
R Shiny 开发人员平台
R Shiny 为 R 开发人员引入了一个平台,可以创建基于 JavaScript 的 Web 应用程序,而无需涉及 JavaScript,或者即使精通 JavaScript 也无需涉及。
为了构建我们的应用程序,我们将利用 R Shiny,并创建一个接口来连接我们在前一节中设置的 CMS Open Payments 数据。
如果您正在使用自己的 R 安装(本地),您需要安装一些 R 软件包。请注意,如果您使用的是 Linux 工作站,可能需要安装一些额外的 Linux 软件包。例如,在 Ubuntu Linux 中,您需要安装以下软件包。您可能已经安装了其中一些软件包,如果是这样,您将收到一条消息,指示对应软件包不需要进一步更改:
sudo apt-get install software-properties-common libssl-dev libcurl4-openssl-dev gdebi-core rlwrap
如果您正在使用 Packt 数据科学 VM,您可以直接进行应用程序开发,因为这些 Linux 软件包已经为您安装好了。
Shiny 应用程序需要一些额外的 R 软件包来提供其所有功能。请注意,R 软件包与前面描述的 Linux 软件包不同。数以千计的 R 软件包为特定学科领域提供专门的功能。对于 Web 应用程序,我们将安装一些 R 软件包,以便利用 Web 应用程序中的一些功能。
以下步骤概述了创建 Web 门户的过程:
- 登录到 RStudio。如果您使用 Packt Data Science VM,请转到
http://localhost:8787/auth-sign-in
。使用用户 ID packt 和密码 packt(与用户 ID 相同)登录。
请注意,如果您已在本地安装了 RStudio,则不会有单独的登录屏幕。该说明纯粹适用于 Packt Data Science VM:
登录到 RStudio 服务器(仅适用于 Packt VM)
如果收到错误消息,说明无法加载该站点,可能是因为端口转发尚未设置。要解决此问题,请进行以下更改:
-
在 VirtualBox 中,右键单击 VM 并选择设置。
-
点击设置下的网络,并展开高级旁边的箭头:
设置 VM 参数
- 点击端口转发并添加规则,将端口 8787 从 VM 转发到主机。必须添加标记为 Packt Rule 的规则,如下所示:
配置端口转发
- 登录后,您将看到以下屏幕。这是 RStudio 的界面,您将使用它来完成练习。我们将在后面的章节中更详细地讨论 R 和 RStudio,本节说明了创建基本 Web 应用程序的过程:
RStudio 控制台
-
安装必要的 R 包。点击文件|R 脚本并复制并粘贴以下代码。
-
然后,点击源以执行以下行:
install.packages(c("shiny","shinydashboard","data.table",
"DT","rjson","jsonlite","shinyjs","devtools"))
library(devtools)
devtools::install_github('kxsystems/rkdb', quiet=TRUE)
通过 RStudio 在 R 中安装所需的包
- 点击文件|新建文件|Shiny Web App:
创建新的 RShiny 应用程序
- 在“应用程序名称”下键入
cmspackt
,然后点击“创建”:
为 RShiny 应用程序指定名称
这将在主目录中创建一个cmspackt
文件夹,如下所示:
R Shiny 应用程序的 app.R 文件
- 将以下代码复制并粘贴到
app.R
部分中:
# # This is a Shiny web application. You can run the application by clicking # the 'Run App' button above. # # Find out more about building applications with Shiny here: # # http://shiny.rstudio.com/
#
# This is a Shiny web application. You can run the application by clicking
# the 'Run App' button above.
#
# Find out more about building applications with Shiny here:
#
# http://shiny.rstudio.com/
#
library(shiny)
library(shinydashboard)
library(data.table)
library(DT)
library(rjson)
library(jsonlite)
library(shinyjs)
library(rkdb)
ui <- dashboardPage (skin="purple", dashboardHeader(title = "CMS Open Payments 2016"),
dashboardSidebar(
useShinyjs(),
sidebarMenu(
uiOutput("month"),
uiOutput("company"),
uiOutput("product"),
uiOutput("state"),
uiOutput("city"),
uiOutput("showData"),
uiOutput("displayColumns"),
uiOutput("aggregationColumns"),
actionButton("queryButton", "View Results")
)
),dashboardBody(
tags$head(tags$link(rel = "stylesheet", type = "text/css", href = "packt.css")),
textOutput("stats"),
dataTableOutput("tableData")
),
title = "CMS Open Payments Data Mining"
)
# Define server logic required to draw a histogram
server <- function(input, output, session) {
h <- open_connection("localhost","5001")
minDate <- execute(h,"minDate")
maxDate <- execute(h,"maxDate")
startDate <- minDate
endDate <- startDate + 31
cmsdata <- data.table(dbColumns=c("month","date","firstName","lastName","city","state","company","product","category","payment","paymentNature"), webColumns=c("Month","Date","First Name","Last Name","City","State","Company","Product","Category","Payment","Payment Nature"))
companyData <- execute(h,"exec distinct showCompany from alldata")
gbyVars <- c("Company","Product","State","City","Category","Payment Nature")
PLACEHOLDERLIST <- list(
placeholder = 'Please select an option below',
onInitialize = I('function() { this.setValue(""); }')
)
PLACEHOLDERLIST2 <- list(
placeholder = 'Select All',
onInitialize = I('function() { this.setValue(""); }')
)
output$month <- renderUI({
dateRangeInput("date", label = 'PAYMENT DATE', start = startDate, end = endDate, min = minDate, max = maxDate)
})
output$company <- renderUI({
selectizeInput("company","COMPANY" , companyData, multiple = TRUE,options = PLACEHOLDERLIST)
})
output$product <- renderUI({
productQuery <- paste0("getShowInfo(`product;\"",paste(input$company,collapse="|"),"\")")
productVals <- execute(h,productQuery)
selectizeInput("product", "DRUG/PRODUCT" , productVals, multiple = TRUE,options = PLACEHOLDERLIST2)
})
output$state <- renderUI({
stateQuery <- paste0("getShowInfo(`state;\"",paste(input$company,collapse="|"),"\")")
stateVals <- execute(h,stateQuery)
selectizeInput("state", "STATE" , stateVals, multiple = TRUE,options = PLACEHOLDERLIST2)
})
output$city <- renderUI({
cityQuery <- paste0("getShowInfo(`city;\"",paste(input$company,collapse="|"),"\")")
cityVals <- execute(h,cityQuery)
selectizeInput("city", "CITY" , cityVals, multiple = TRUE,options = PLACEHOLDERLIST2)
})
output$showData <- renderUI({
selectInput("showData", label = "DISPLAY TYPE", choices = list("Show Data" = 1, "Aggregate Data" = 2), selected = 1)
})
output$displayColumns <- renderUI({
if (is.null(input$showData)) {selectInput("columns", "SHOW DATA",cmsdata$webColumns, selectize = FALSE, multiple = TRUE, size=11)}
else if(input$showData == 1) {selectInput("columns", "SHOW DATA",cmsdata$webColumns, selectize = FALSE, multiple = TRUE, size=11) }
else if(input$showData == 2) {selectInput("aggVars", "AGGREGATE DATA",gbyVars, selectize = FALSE, multiple = TRUE, size=6) }
})
output$aggregationColumns <- renderUI ({ conditionalPanel(
condition = "input.showData != 1",
selectInput("aggData", "CALCULATE METRICS" , c("Total Payment","Number of Payments","Minimum Payment","Maximum Payment","Average Payment"), selectize = TRUE, multiple = TRUE)
)})
getTableData <- eventReactive(input$queryButton, {
disable("queryButton")
queryInfo <- (list(date=as.character(input$date),company=input$company, product=input$product, state=input$state, city=input$city,columns=cmsdata$dbColumns(cmsdata$webColumns %in% input$columns),showData=input$showData))
if (input$showData !=1) {queryInfo <- c(queryInfo, list(aggVars=cmsdata$dbColumns(cmsdata$webColumns %in% input$aggVars), aggData=input$aggData))} else {queryInfo <- c(queryInfo)}
JSON <- rjson::toJSON(queryInfo)
getQuery <- paste0("getRes \"",URLencode(JSON),"\"")
finalResults <- execute(h,getQuery)
enable("queryButton")
print (finalResults)
fres <<- finalResults
print (class(finalResults((1))))
print (finalResults)
finalResults
})
output$tableData <- renderDataTable({ datatable(getTableData()((1)))})
output$stats <- renderText({(getTableData())((2))})
}
# Run the application
shinyApp(ui = ui, server = server)
- 点击右下角的新文件夹:
创建 CSS 文件夹
- 将新文件夹重命名为
cmspackt/www
,如下所示:
为文件夹指定名称
- 点击文件|新建文件|文本文件:
创建 CSS 文件
- 复制并粘贴以下代码:
.shiny-text-output, .shiny-bount-output {
margin: 1px;
font-weight: bold;
}
.main-header .logo {
height: 20px;
font-size: 14px;
font-weight: bold;
line-height: 20px;
}
.main-header .sidebar-toggle {
padding: 0px;
}
.main-header .navbar {
min-height: 0px !important;
}
.left-side, .main-sidebar {
padding-top: 15px !important;
}
.form-group {
margin-bottom: 2px;
}
.selectize-input {
min-height: 0px !important;
padding-top: 1px !important;
padding-bottom: 1px !important;
padding-left: 12px !important;
padding-right: 12px !important;
}
.sidebar {
height: 99vh;
overflow-y: auto;
}
section.sidebar .shiny-input-container {
padding: 5px 15px 0px 12px;
}
.btn {
padding: 1px;
margin-left: 15px;
color:#636363;
background-color:#e0f3f8;
border-color:#e0f3f8;
}
.btn.focus, .btn:focus, .btn:hover {
color: #4575b4;
background-color:#fff;
border-color:#fff;
}
pre {
display: inline-table;
width: 100%;
padding: 2px;
margin: 0 0 5px;
font-size: 12px;
line-height: 1.42857143;
color: rgb(51, 52, 53);
word-break: break-all;
word-wrap: break-word;
background-color: rgba(10, 9, 9, 0.06);
border: 1px rgba(10, 9, 9, 0.06);
/* border-radius: 4px */
}
.skin-red .sidebar a {
color: #fff;
}
.sidebar {
color: #e0f3f8;
background-color:#4575b4;
border-color:#4575b4;
}
- 点击文件|另存为以保存文件,如下所示:
为 CSS 文件选择另存为
- 另存为
/home/packt/cmspackt/www/packt.css
,如下所示:
保存 CSS 文件
您的应用程序现在已准备就绪!
将所有内容放在一起- CMS Open Payments 应用程序
在之前的部分中,我们已经学习了如何:
-
下载数据集
-
创建后端数据库
-
为后端数据库创建代码
-
设置 RStudio
-
创建 R Shiny 应用程序
要启动应用程序,请完成以下步骤:
-
启动 Q 应用程序,确保您在主目录中。键入 pwd 并按 Enter。这将显示
/home/packt
的当前工作目录,如下图所示。 -
接下来,键入
q
并按 Enter。 -
在
q
提示符下,键入\l cms.q
。
请注意,cms.q
是我们在开发 Q 应用程序时在早期部分创建的文件。
脚本将加载数据库并返回到q)
提示:
将所有内容放在一起:在 KDB+会话中加载 CMS KDB+ Q 脚本
-
启动 CMS Open Payment 应用程序
-
在 RStudio 中打开包含 R 代码的
app.R
文件,并点击右上角的 Run App,如下所示:
运行 RShiny 应用程序
这将启动 Web 应用程序,如下所示:
RShiny 应用程序
我们现在已经完成了开发一个完整的 CMS Open Payments 应用程序,允许最终用户过滤、聚合和分析数据。现在,您可以通过在屏幕上选择各种选项来运行查询。应用程序有两个功能:
-
过滤数据(默认视图)
-
聚合数据(您可以通过从显示类型菜单中选择聚合数据切换到此选项)
应用程序
过滤示例:查看某家公司在纽约州为某种药物支付的款项:
使用 RShiny 应用程序
请注意,系统在标题消息中显示处理了 1100 万条记录,用时 21 毫秒。出于隐私原因,屏幕截图中的公司名称和产品名称已被隐藏,但您可以自由尝试不同的选项。
请注意,在默认的虚拟机中,我们只使用了一个内核和非常有限的内存,即使在具有非常有限资源的笔记本电脑上,使用 kdb+处理数据的速度也轻松超过了许多富裕的商业解决方案的性能。
聚合示例:选择聚合数据和计算指标字段的选项,以查看按州、支付类别和支付性质分组的总付款额,针对特定公司和产品。请注意,出于隐私原因,屏幕截图中的公司名称和产品名称已被隐藏。
请注意顶部的消息,其中说明:
记录指示查询和应用程序性能
这表明了底层 kdb+数据库处理数据的速度。在这种情况下,它使用给定的选项在 22 毫秒内过滤和聚合了 1100 万条记录。
CMS OpenPayments 应用程序截图
摘要
本章介绍了 NoSQL 的概念。这个术语近年来变得越来越流行,特别是由于它与大数据分析的相关性和直接应用。我们讨论了 NoSQL 中的核心术语、它们的各种类型以及行业中用于这些功能的流行软件。最后,我们通过使用 MongoDB 和 kdb+进行了几个教程。
我们还使用 R 和 R Shiny 构建了一个应用程序,以创建一个动态的 Web 界面,与加载在 kdb+中的数据进行交互。
下一章将介绍当今数据科学中另一个常见的技术,即 Spark。这是另一个工具包,如今赋予全球数据科学家们力量。