PIG-设计模式-全-

PIG 设计模式(全)

原文:Pig design patterns

协议:CC BY-NC-SA 4.0

零、前言

这本书是实现大数据分析能力的实用指南。它指导您的大数据技术专家完成准备数据、应用分析和从数据中创造价值的过程。所有这些都是通过在 Pig 中使用适当的设计模式来完成的。我们选择 Pig 来证明它有多有用,这可以从以下几点清楚地看出:

  • Pig 通过其简单的语言构造具有内在的可修改性,非常容易学习,其可扩展性和对结构化和非结构化大数据的适用性使其成为首选。
  • Pig 可以轻松快速地实现模式,并从任何大数据中明显的随机性中获得意义,这是值得称赞的。
  • 本书指导系统架构师和开发人员更熟练地使用 Pig 创建复杂的分析解决方案。它通过让他们接触各种 Pig 设计模式、UDF、工具和最佳实践来做到这一点。

通过阅读这本书,你将实现以下目标:

  • 通过跨平台执行数据移动、数据接收、分析、验证、转换、数据缩减和输出,简化创建复杂数据管道的流程;你也可以在这些设计模式中使用 Pig。
  • 创建解决方案,使用模式对多结构未建模数据进行探索性分析,从而从中导出结构,并将数据移动到下游系统进行进一步分析。
  • 解释 Pig 如何与 Hadoop 生态系统中的其他工具共存,使用设计模式创建大数据解决方案。

这本书包括什么?

第一章在 PIG中设定了设计模式的脉络,为设计模式奠定了基础。Hadoop、MapReduce 及其生态系统组件逐渐暴露了 Pig、其数据流范式以及使 Pig 工作所需的语言结构和带有几个基本示例的概念。它为了解 Pig 最适合的各种工作负载以及 Pig 如何得分提供了背景。如果你有足够的动力去学习更多关于 PIG 的知识,这一章更多的是一个快速实用的参考,并指出更多的参考。

第二章数据摄取输出模式说明了处理各种数据源的数据摄取输出设计模式。本章包括具体的例子,说明了与外部系统集成的技术,该技术发送多结构和结构化的数据,并使用 Hadoop 作为接收点。本章还讨论了将数据从 Hadoop 导出到外部系统的模式。为了解释这些接收和输出模式,我们考虑了几种文件系统,包括但不限于日志文件、JSON、XML、MongoDB、Cassandra、HBase 等常见的结构化数据源。阅读本章后,您将能够更好地对企业环境中与接收和输出相关的模式进行编程,并且您可以通过使用正确的 Pig 编程或编写自己的 UDF 程序来应用这些知识来构建这些模式。

第三章数据分析模式重点介绍了适用于各种数据格式的数据分析模式,并在 Pig 中实现了这些模式。这些模式包括 Pig 的不同方法、分析数据和发现数据质量问题的基本和创新统计技术。您将学习如何使用 Pig 在您的企业环境中编程类似的模式,并编写自己的 UDF 来扩展这些模式。

第四章数据校验与清理模式是关于适用于各种数据格式的数据校验与清理模式。验证模式处理约束、正则表达式和其他统计技术。数据清理模式处理简单过滤器、布隆过滤器和其他统计技术,为应用转换准备数据。

第五章数据转换模式涉及 Hadoop 中应用于各种数据类型的数据转换模式。阅读本章后,您将能够选择基本转换的正确模式,并了解广泛使用的概念,例如创建连接、汇总、聚合、立方体、汇总数据、泛化和属性构造,必要时使用 Pig 的编程构造和 UDF。

第 6 章了解数据约简模式并解释应用于已被摄取、清理和转换的数据的数据约简模式。阅读本章后,您将能够理解并使用模式进行降维、采样技术、宁滨、聚类和无关属性约简,从而为数据分析做好准备。本章讨论了使用 Pig 语言的各种技术,并扩展了 Pig 的功能,以提供复杂的数据简化用法。

第七章高级模式及未来工作涉及高级数据分析模式。这些模式涵盖了 Pig 语言的可扩展性,并用案例解释了与可执行代码集成的方法,映射了用 Java 编写的 reduce 代码,来自 PiggyBank 的 UDF 等来源。高级分析涵盖与自然语言处理、聚类、分类和文本索引相关的模式。

这本书的动机

写这本书的灵感来源于我以工作为生,即引领大数据的企业实践,参与基于大数据技术栈的解决方案的创新和交付。

作为这个角色的一部分,我参与了许多用例、解决方案架构的试点以及许多大数据解决方案的开发。根据我的经验,Pig 是一种灵感,对于想要快速测试一个用例并向业务展示价值的用户有很大的吸引力。我用 Pig 证明了快速盈利,解决了需要不太陡峭的学习曲线的问题。同时我发现企业使用 Pig 的书面知识在某些情况下是不存在的,如果有这样的知识会广泛传播。个人认为有必要有一本基于用例模式的知识参考书。通过这本书,我想分享我的经验和教训,并从模式的角度向你传达 Pig 在解决你常见问题方面的可用性和优势。

之所以选择写 Pig 的设计模式,还有一个原因是我对 Pig 语言着迷,它的简单性、通用性和可扩展性。我一直在企业环境中寻找一个可重复的 Pig 食谱模式,这启发我将其记录下来,以便更广泛地使用。我想通过贡献一个 Pig 的模式库来传播我在使用 Pig 时学到的最佳实践。我对在各种用例中使用 Pig 的无形可能性非常感兴趣。通过这本书,我计划进一步扩大它的应用范围,让 Pig 更快乐地工作。

这本书描述了学习 PIG 的实际和实用方面。它为大数据企业中的常见挑战提供了特定的可重用解决方案。它的目标是指导您快速将 Pig 的使用映射到您的问题上下文,并从设计模式的角度设计端到端的大数据系统。

在本书中,设计模式是一组逻辑连接的企业用例,因此它们可以被分解成易于遵循的离散解决方案,并且可以由 Pig 解决。这些设计模式解决了复杂数据管道的创建、进入、退出、转换、迭代处理、合并和海量数据分析等常见的企业问题。

这本书增强了您对特定设计模式的适用性做出更好决策的能力,并使用 Pig 来实现解决方案。

Pig 拉丁语一直是复杂数据管道、数据迭代处理和研究的首选语言。所有这些用例都包括连续的步骤,在这些步骤中,数据被获取、清理、转换并提供给上游系统。成功地创建一个复杂的管道来集成来自不同结构的多个数据平台的倾斜数据,是任何企业利用大数据并通过分析从中创造价值的基石。

这本书使您能够使用这些设计模式来简化 Pig 的使用,以创建复杂的数据管道,从多个数据源获取数据,清理、分析、验证、转换并最终呈现大量数据。

本书使用用 Java 编写的 Pig 和 UDF 的集成提供了深入的解释和代码示例。每一章都包含一组设计模式来提出和解决与企业用例相关的技术挑战。这些章节彼此相对独立,可以以任何顺序完成,因为它们是根据企业中一组常见步骤的特定设计模式设计的。例如,期待解决数据转换问题的读者可以直接访问的第 5 章和数据转换模式,快速开始使用本章提到的代码和说明。这本书建议你使用这些模式来解决你遇到的相同或相似的问题。如果设计模式不适合特定的情况,创建自己的模式。

这本书的目的不是作为一个完整的 Pig 编程指南,而是作为一本参考书,介绍将 Pig 应用于设计模式的思想。它还旨在使您能够创造性地使用设计模式,并使用它们构建有趣的混搭。

这本书你需要什么?

您将需要访问单个机器(虚拟机)或多节点 Hadoop 集群来执行本书中给出的 Pig 脚本。预计将配置运行 Pig 所需的工具。我们已经用 Pig 0.11.0 测试了本书中的示例,强烈建议您安装此版本。

本书中的 UDF 代码是用不同的语言编写的,比如 Java。因此,允许您使用熟悉的开发工具访问机器是明智的,例如 Eclipse。

建议在开发人员的机器上使用 Pig Pen (Eclipse 插件)来开发和调试 Pig 脚本。

The pen can be downloaded from https://issues. Apache. org/jira/secure/attachment/12456988/org。 Apache. Pig. Pen _ 0. 7 .5. Can download.

这本书是给谁的?

这本书是为已经熟悉 Pig 的有经验的开发者写的。他们期望从用例的角度,能够把企业遇到的数据接收、分析、清理、转换、输出问题联系起来。Pig 的这些超级用户会以这本书为参考,了解 Pig 设计模式对于解决他们的问题的意义。

Hadoop 和 Pig 知识对于您更好地掌握 Pig 设计模式的复杂性是强制性的。为了解决这个问题,的第一章和在 PIG 中设置了设计模式的上下文,其中包含了介绍性的概念,并附有简单的例子。建议读者熟悉 Java 和 Python,以便更好地理解在许多章节中用作示例的 UDF。

约定

在这本书里,你会发现许多区分不同种类信息的文本样式。以下是这些风格及其含义的一些例子。

正文中的码字如下:“从这一点开始,我们将调用解包后的 Hadoop 目录HADOOP_HOME

用 Java 编写的 UDF 代码块设置如下:

package com.pigdesignpatterns.myudfs;

public class DeIdentifyUDF extends EvalFunc<String> {

  @Override
  public String exec(Tuple input){

          try {
                String plainText = (String)input.get(0);
                String encryptKey = (String)input.get(1);
                String str="";
                str = encrypt(plainText,encryptKey.getBytes());
                return str;
              }
              catch (NullPointerException npe) {
                warn(npe.toString(), PigWarning.UDF_WARNING_2);
                return null;
              } catch (StringIndexOutOfBoundsException npe) {
                warn(npe.toString(), PigWarning.UDF_WARNING_3);
                return null;
              } catch (ClassCastException e) {
                warn(e.toString(), PigWarning.UDF_WARNING_4);
                return null;
              }

PIG 脚本如下所示:

Users = load 'users' as (name, age); 
Fltrd = filter Users by
 age >= 18 and age <= 25; 
Pages = load 'pages' as (user, url); 
Jnd = join Fltrd by name, Pages by user; 
Grpd = group Jnd by url; 
Smmd = foreach Grpd generate group, 
COUNT(Jnd) as clicks; 
Srtd = order Smmd by clicks desc; 
Top5 = limit Srtd 5; 
store Top5 into 'top5sites'

任何命令行输入或输出都编写如下:

>tar -zxvf hadoop-1.x.x.tar.gz

新名词重要词汇以粗体显示。您在屏幕上看到的单词,例如菜单或对话框中的单词,出现在以下文本中:“单击下一步按钮进入下一个屏幕。”

否则这样的盒子里会出现一个重要的警告。

技巧和技巧是这样出现的。

读者反馈

欢迎读者反馈。让我们知道你对这本书的看法——你喜欢或不喜欢什么。读者的反馈对我们开发标题非常重要,你可以从中真正获得最大的好处。

要给我们发送一般反馈,只需发送电子邮件至<[feedback@packtpub.com](mailto:feedback@packtpub.com)>并通过您消息的主题提及书名即可。

如果您对某个主题有专业知识,并且有兴趣写作或投稿,请参考我们在www.packtpub.com/authors的作者指南。

客户支持

现在,您很自豪拥有一本书,我们有很多东西可以帮助您从购买中获得最大收益。

下载示例代码

你可以下载你在http://www.packtpub.com账户购买的所有 Packt 书籍的样本代码文件。如果你是在外地买的这本书,可以访问http://www.packtpub.com/support注册,通过邮件直接把文件发给你。本书中的例子是通过为 Pig 0 . 11 . 0 版本编译来测试的。许多 Pig 脚本、UDF 和数据都可以从发行商的网站或 GitHub 上获得。

也可以使用https://github.com/pradeep-pasupuleti/pig-design-patterns

PIG 脚本的例子按照章节组织在各自的目录中。Java 和 Python 的 UDF 也是章节目录的一部分,并被组织在一个名为src的单独子目录中。所有数据集都在数据集目录中。包括自述文件,以帮助您建立 UDF 和理解数据文件的内容。

每个脚本都是在假设输入和输出都在 HDFS 路径上的情况下编写的。

第三方库

为了方便起见,使用了许多第三方库。它们包含在 Maven 依赖项中,因此使用这些库不需要额外的工作。下表列出了在整个代码示例中常用的库:

|

库名

|

形容

|

戒指

|
| --- | --- | --- |
| 数据单元 | 数据单元是用户自定义函数的集合,用于处理 Hadoop 和 Pig 中的大规模数据,尤其是数据挖掘和统计。 | http://search.maven.org/remotecontent?file 路径= com/LinkedIn/data fu/data fu/0 .0 .10/数据 fu-0 .0 .10 .罐子 |
| Mungo -hadoop Akin | 这是 Hadoop 的一个插件,它提供了使用 MongoDB 作为输入源和/或输出源的能力。 | http://repo 1 .梅文 org/maven 2/org/MongoDB/Mongo-Hadoop-core _ 1 .0 . 0/1 . 0 . 0-rc0/mongo-Hadoop-core _ 1 .0 .0-1 .0 .0-rc0 .罐子 |
| 蒙古-Hadoop-PIG | 这是为了从 MongoDB 数据库中加载记录,以便它们可以在 Pig 脚本中使用并写入 MongoDB 实例。 | http://repo 1 .梅文 org/maven 2/org/MongoDB/Mongo-Hadoop-pig/1 .0 .0/mongo-Hadoop-pig-1 .0 .0 .罐子 |
| Mongo-Java-驱动程序 | 这是 MongoDB 的一个 Java 驱动程序。 | http://repo 1。苏慕恩梅文 maven .-什么:1 云娥/2 .9 .0/Java mongo 云娥-2.9.0.jar |
| 大象 PIG | 这是 Twitter 的 PIG 装载功能开源库。 | http://repo 1 .梅文 org/maven 2/com/Twitter/象鸟/象鸟-PIG/3 .0 .5/象鸟-PIG-3.0.5.jar |
| 鸟芯 | 这是推特核心实用程序的集合。 | http://repo 1 .梅文 org/maven 2/com/Twitter/象鸟/象鸟-PIG/3 .0 .5/象鸟-PIG-3.0.5.jar |
| hctalog-清管器适配器 | 它包含从 Hcatalog 管理的表中访问数据的实用程序。 | http://search.maven.org/remotecontent?file 路径= org/Apache/h 目录/h 目录-清管器-适配器/0 .11 .0 英里/小时目录-清管器-适配器-0。11 .0 .罐子 |
| cb2java | 这个罐子优酷动态解析 cobol 字帖。 | http://SourceForge .net/project/cb2 Java/file/latest/下载 |
| 罗欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧欧 | 这是 Avro 核心组件库。 | http://repo 1 .梅文 org/maven 2/org/Apache/4 月/4 月/1 .7 .4/4 月-1.7.4.jar |
| json-simple | 这个库是一个用于 JSON 编码或解码 JSON 文本的 Java 工具包。 | http://www .java2s .com/Code/JarDownload/JSON-simple/JSON-simple-1 .1 .1 .罐子。拉链 |
| 公地数学 | 这个库包含很少的数学和统计成分。 | http://repo 1。苏慕恩梅文 maven .文士/maven 2/org/Apache/commons/commons-math 3/3.2/commons-math 3-3.2。jar〔t1〕t1〔t1〕 |

数据集

在本书中,您将使用这些数据集为示例提供一些多样性。可以在 https://github.com/pradeep-pasupuleti/pig-design-patterns 目录的 GitHub 存储库中获得所用确切数据的副本。只要相关,章节特定数据就存在于相同 GitHub 位置下的章节特定子目录中。

以下是数据集的主要分类,它们与本书中讨论的用例相关:

  • The logs dataset contains a month's worth of HTTP requests to the NASA Kennedy Space Center WWW server in Florida. These logs are in the format of Apache access logs.

    数据集从链接ftp://ita.ee.lbl.gov/traces/NASA_access_log_Jul95.gzftp://ita.ee.lbl.gov/traces/NASA_access_log_Aug95.gz下载。

    鸣谢:日志由肯尼迪航天中心的吉姆·杜穆林收集,萨斯喀彻温大学的马丁·朴正洙(<[mfa126@cs.usask.ca](mailto:mfa126@cs.usask.ca)>)和凯里·威廉姆森(<[carey@cs.usask.ca](mailto:carey@cs.usask.ca)>)提供。

  • 自定义日志数据集包含由 web 应用以自定义日志格式生成的日志。事件日志中嵌入了 Web 服务请求和响应信息。这是一个专门为说明本书中的例子而创建的复合数据集。

  • The historical NASDAQ stock data from 1970 to 2010, including daily open, close, low, high, and trading volume figures. Data is organized alphabetically by ticker symbol.

    本数据集下载自链接 http://www .信息黑猩猩. com/dataset/Nasdaq-exchange-daily-1970-2010-开盘-收盘-高-低-成交量/下载量/166853

  • 客户零售交易数据集包含购买产品类别的详细信息和客户人口统计信息。这是一个专门为说明本书中的例子而创建的复合数据集。

  • 汽车保险索赔数据集由两个文件组成。automobile_policy_master.csv单据中包含车辆的价格和为此支付的保费。文件automobile_insurance_claims.csv包含了汽车保险的理赔数据,具体是车辆修理费的理赔。这是一个专门为说明本书中的例子而创建的复合数据集。

  • The MedlinePlus health topic XML files contain records of health topics. Each health topic record includes data elements associated with that topic.

    该数据集可从链接 http://www .健康数据. gov/data/dataset/medlineplus-health-topic-XML-files-0下载。

  • This dataset contains a large set of e-mail messages from the Enron corpus which has about 150 users with an average of 757 messages per user; the dataset is in AVRO format and we have converted it to JSON format for the purpose of this book.

    本数据集下载自链接 S3 .亚马逊 com/rjurney _ public _ web/Hadoop/Enron .avro

  • 电器制造数据集是为了本书的目的而创建的复合数据集。此数据集包含以下文件:

    • manufacturing_units.csv:包含每个制造单元的信息。
    • products.csv:包含产品的详细信息。
    • manufacturing_units_products.csv:保存不同制造单位生产的产品的详细信息。
    • production.csv:这里保存生产明细。
  • 非结构化文本数据集包含一些来自维基百科的关于计算机科学和信息技术、大数据、医学、电话发明、停用词列表和词典词表的文章。

  • Outlook 联系人数据集是一个复合数据集,它是出于本书的目的通过导出 Outlook 联系人而创建的;它是一个带有属性联系人名称和标题的 CSV 文件。

  • The German credit dataset in CSV format classifies people as good or bad credit risks based on a set of attributes. There are 20 attributes (7 numerical and 13 categorical) with 1,000 instances.

    数据集可从链接http://archive.ics.uci.edu/ml/machine 学习-数据库/statlog/German/German.data 下载。

    鸣谢:数据来自 UCI 机器学习知识库(http://archive . ics . UCI . edu/ml/datasets/stat og+(德语+Credit+Data)),来源:汉堡大学统计与经济研究所教授汉斯·霍夫曼博士。

勘误表

虽然我们尽最大努力确保内容的准确性,但错误还是会发生。如果你在我们的一本书里发现一个错误——可能是文本或代码中的错误——如果你能向我们报告,我们将不胜感激。通过这样做,你可以让其他读者免受挫折,并帮助我们改进这本书的后续版本。如有勘误,请访问http://www.packtpub.com/support,选择您的图书,点击勘误T4【提交 表格链接,输入您的勘误详情。一旦您的勘误表得到验证,您的提交将被接受,勘误表将被上传到我们的网站或添加到标题勘误表部分下的任何现有勘误表列表中。

盗版

互联网上版权材料的盗版是所有媒体的一个老大难问题。在 Packt,我们非常重视版权和许可证的保护。如果您在互联网上遇到任何形式的非法复制我们的作品,请立即向我们提供位置地址或网站名称,以便我们寻求补救措施。

请联系我们<[copyright@packtpub.com](mailto:copyright@packtpub.com)>获取疑似盗版资料的链接。

我们感谢您在保护我们的作者方面的帮助,以及我们为您带来有价值内容的能力。

问题

如果您对本书有任何疑问,可以在<[questions@packtpub.com](mailto:questions@packtpub.com)>联系我们,我们会尽力解决。

一、为 PIG 的设计模式设定背景

本章旨在对本书涉及的各种技术和概念提供一个宽泛的介绍。我们从探索与设计模式相关的概念开始,通过定义它们并理解它们是如何在现实生活中被发现和应用的,我们寻求理解这些设计模式是如何在 Pig 中被应用和实现的。

在开始研究 Pig 编程语言的复杂性之前,首先要探究 Pig 产生的背景、Pig 在企业中的使用地位以及 Hadoop 如何适应大数据时代的分布式计算环境。然后,我们快速进入 Hadoop 生态系统,向大家介绍它的重要功能。已经从语言特性的角度介绍了 Pig 编程语言,为大家提供了一个现成的例子,详细讲解了语言特性,比如常用运算符、可扩展性、输入输出运算符、关系运算符、模式、空值以及理解中间 MapReduce 代码的方法。

了解设计模式

设计模式为类似的问题或需求提供一致且通用的解决方案。在处理不同的系统时,设计者往往会遇到问题本身的相似性或者需要满足的需求。最终,他/她获得了足够的关于细微变化的知识,并开始看到连接这些不同且反复出现的问题的共同线索。这些共同的行为或特征然后被抽象成一个模式。因此,这种模式或解决方法是一种通用设计,也可以应用于更广泛的需求集和新形式的问题。比如广受好评的《软件设计模式》Erich GammaRichard HelmRalph JohnsonJohn VlisidesAddison-Wesley Professional编写的《设计模式:可重用面向对象软件的要素》一书,这些模式也可以通过分析现实生活中追溯到非软件领域的情况来理解。本书中提到的工厂方法模式定义了一个创建类对象的接口,但是它让子类决定实例化哪个类。这种软件模式在非软件行业似乎有相似之处,玩具都是通过注塑成型的。该机器加工塑料粉末,并将粉末注射到所需形状的模具中。玩具的类型(汽车、动作人物等)。)是由他们的模具决定的。

设计模式不是为了解决一个特定的问题,这个问题可以像一个完美的定制解决方案一样转换成代码。相反,它就像一个模板,用来解决特定的、定义明确的问题。通常,设计模式是在现实生活中发现的;他们不是被创造出来的。以下是发现模式的一般方法:

  • 共同解决最新问题的一组新技术的演变;这些技术认为需要一个模式目录。
  • 反复出现的问题的解决方案

使现有模型适应新的情况,并修改现有模型本身。找到一个模式意味着定义它,给它一个名字,并以一种非常清晰的方式记录下来,以便用户在面临类似问题时能够阅读、理解和应用它们。当一个模式被真实用户使用,并且他们已经解决了现实世界的问题而不是假设的问题时,它是值得发布的。这些模式不是规则或法律;它们是指导原则,可以根据解决方案的需要进行修改。

这本书的灵感来自其他不同主题领域的设计模式书籍。它也遵循 GoF 模式目录设计模式:可重用的面向对象软件元素、由 GammaHelmJohnson&Foley Sieders(Addison-Wesley 专业版)勾勒的模式文档格式。

本书中的每个设计模式都遵循一个模板,并由一个名称标识,后面是几个部分,告诉用户更多关于模式的信息。

  • 名称模式提供了一个唯一的标识符,这是一种很好的交流方式。
  • 模式的细节部分简要描述了模式的内容和原因。
  • 背景描述模型的动机和详细适用性。
  • 动机描述一个具体的场景,描述问题以及模式如何适合作为解决方案。适用性描述了使用模式的不同情况。
  • 用例处理真实系统中的各种用例,在这些用例中我们可以看到模式的证据。
  • 代码片段的部分由实现该模式的代码组成。
  • 结果包含模式的结果,处理模式输出的预期和意外效果。
  • 附加信息部分加工模式相互关联,以及与模式相关的任何其他相关信息。

当您识别出一个问题时,您应用了一个模式,一个模式可以解决这个问题,并识别与其他问题的相似性,这些问题可以通过使用已知的模式来解决。这可能发生在初始设计、编码或维护阶段。要做到这一点,你需要熟悉现有的模式及其关系,然后看背景部分,深入研究模式设计问题的动机和适用性。

PIG 的设计模式范围

本书讨论了在企业环境中解决现实世界中反复出现的大数据问题时遇到的模式。对这些模式的需求根植于 Pig 的发展,以解决大量数据的新兴问题,以及对模式目录的感知需求来记录他们的解决方案。

在处理大量数据时遇到的问题通常涉及到牢牢把握数据是否可以用来生成分析意见,如果可以,如何高效地生成这些意见。把自己想象成一个数据科学家,他得到了大量的数据,这些数据没有合适的模式,无序,长时间没有被记录。要求您将其与其他企业数据源集成,并生成引人注目的分析见解。你怎么开始?你会开始整合数据,开始你最喜欢的分析沙盒,并开始产生结果吗?如果你提前知道设计模式的存在,并且在这种情况下可以系统有序的应用这些模式,以减少错误,提高大数据分析的效率,你会觉得方便吗?在这种情况下,本书讨论的设计模式肯定会吸引你。

Pig 中的设计模式旨在提高你处理大数据问题的能力,快速应用模式解决问题。使用 Pig 成功开发大数据解决方案需要在开发生命周期的早期阶段考虑问题,这些模式有助于发现这些问题。重用 Pig 设计模式可以帮助识别和解决这些微妙之处,并防止它们发展成主要问题。模式应用的副产品是最终代码的可读性和可维护性。这些模式为开发人员提供了一个有价值的交流工具,允许他们使用一个通用的词汇表来讨论模式可以解决的问题,而不是用冗长的方式解释问题的内部。PIG 的设计模式不是成功的食谱;它们是经验法则。阅读本书中关于 Pig 设计模式的具体案例,可能有助于你尽早发现问题,从而避免未来指数级的返工成本。

设计模式的流行很大程度上取决于领域。比如四人帮书中的状态模式、代理、外观,在与其他系统进行通信的应用中非常常见。同样,使用大数据来理解分析意见的企业使用与解决数据管道问题相关的模式,因为这是一个非常常见的用例。这些模式具体描述了 Pig 在数据接收、分析、清理、转换、还原、分析和输出中的应用。

第 5 章讨论的几种模式数据转换模式第 6 章了解数据约简模式,使已有模式适应新情况,并在过程中对已有模式本身进行修改。这些模式处理 Pig 在增量数据集成和快速原型开发中的使用。

这些设计模式也更深入,使您能够确定 Pig 的特定语言结构对给定问题的适用性。以下问题更好地说明了这一点:

  • 解决特定模式投影的推荐用法是什么?
  • 标量投影在哪种模式下最适合访问聚合?
  • 哪些模式不建议使用COUNTSUMCOUNT_STAR
  • 在关键点分布不均的格局中,如何有效利用排序?
  • 哪些模式与溢出数据类型的正确使用有关?
  • 当不使用多个FLATTENS操作符时,会导致CROSS出现在袋子上?
  • 有哪些模式描述了嵌套FOREACH方法的理想用法?
  • 当一个数据集可以存入内存时,JOIN操作选择哪些模式?
  • 当一个键在连接关系中占主导地位时,JOIN操作应该选择哪种模式?
  • 两个数据集排序后,JOIN操作选择哪些模式?

Hadoop 揭开神秘面 Yarn——一个快速计算器

现在,我们将讨论处理巨大的多结构数据的需求,以及用传统的分布式应用处理如此巨大的数据所涉及的挑战。我们还将讨论 Hadoop 的出现以及它如何有效地应对这些挑战。

企业背景

过去的十年是数据史上的决定性时刻,引领企业采用新的商业模式,利用大规模数据增长带来的机遇。

互联网搜索、个性化音乐、平板电脑、智能手机、3G 网络和社交媒体的激增,推动了数据管理规则的变化,从数据的组织、获取、存储和检索的角度转向管理。需要对这些新的数据源进行决策并获得有价值的见解,这已经成为企业武库中的一件有价值的武器,旨在企业取得成功。

基于关系数据库管理系统的数据仓库等传统系统率先支持决策过程,可以应用传统的统计度量方法对数据进行收集、存储和管理,从而创建了一个报告和分析平台。这些传统系统收集的数据本质上是高度结构化的,随着新兴数据类型的需求而变化的灵活性极低,而新兴数据类型的非结构化程度更高。

这些数据仓库可以支持分布式处理应用,但是有很多限制。这种分布式处理应用通常面向获取结构化数据,对其进行转换并使其可用于分析或报告,这些应用主要是批处理作业。在某些情况下,这些应用运行在机器集群上,将计算和数据分发到集群的节点。这些应用获取大量数据,对其执行计算密集型操作,并将其发送到下游系统,供另一个应用或系统使用。

随着对结构化和非结构化数据分析和洞察的竞争需求,当前企业需要处理前所未有的海量数据。该处理主要涉及执行清理、分析和转换非结构化数据和企业数据源所需的操作,以便结果可用于获得有用的分析见解。处理这些大型数据集需要许多中央处理单元、足够的输入/输出带宽、内存等。另外,每当有大规模的治疗,就意味着我们要应对各种失败。传统的系统,如关系数据库管理系统,在如此巨大的数据负载下或数据变化不可预测的情况下,无法进行线性或经济高效的扩展。

为了应对数据的异常涌入,显然需要数据管理技术解决方案;这使我们能够在短时间内以不同的复杂程度消费多种格式的大量数据,从而创建一个强大的分析平台来支持决策。

分布式系统的常见挑战

在 Hadoop 出现之前,分布式应用试图应对数据增长和并行处理的挑战,其中处理器、网络和存储故障屡见不鲜。分布式系统通常必须管理生态系统中每个组件的故障,这些故障是由磁盘空间不足、数据损坏、性能下降、路由问题和网络拥塞引起的。在传统架构中几乎不可能实现线性可扩展性,在有限的可能性下也不是没有很大的成本。

高可用性是以牺牲可扩展性或完整性为代价实现的。缺乏对并发性、容错性和数据可用性的良好支持,不利于处理大数据的传统系统的复杂性。此外,如果我们要部署一个包含最新预测算法的定制应用,分布式代码有其自身的同步、锁定、资源争用、并发控制和事务恢复等问题。

在关系数据库管理系统的传统数据仓库系统中,以前讨论的分布式计算问题很少以多种方式处理,但这些解决方案不能直接扩展到大数据的情况。在这种情况下,由于数据量巨大及其多样性和速度,问题将呈指数级放大。数量问题在一定程度上是可以解决的。然而,数据多样性和数据速度的问题非常昂贵,并且不能通过这些控制传统系统来解决大数据问题的尝试来解决。

随着时间的推移,问题越来越大,处理大数据的解决方案被分布式处理、分布式存储、人工智能、多处理器系统、面向对象概念和互联网数据处理技术等多种技术的智能结合所接受。

Hadoop 的出现

Hadoop 是一个可以容忍机器故障的框架。它是为了克服前面讨论的分布式系统的挑战而构建的。Hadoop 提供了一种使用机器集群并行存储和处理海量数据的方法。它是一种基于文件系统的可扩展分布式数据处理架构,设计并部署在高吞吐量和可扩展的基础设施上。

Hadoop 起源于 Google,Google 创造了一种新的计算模型,基于文件系统 Google 文件系统 ( GFS ) 和编程框架 MapReduce,扩展了搜索引擎的规模,可以同时处理多个查询。 Doug CuttingMike Cafarella 改编了谷歌的这个计算模型,重新设计了他们名为 Nutch 的搜索引擎。这最终导致了 Nutch 作为开源下的顶级 Apache 项目的发展,2006 年被雅虎采用,最终转化为 Hadoop。

以下是 Hadoop 的主要特性:

  • Hadoop 给大众带来了尴尬的大规模并行处理能力。
  • 通过使用文件系统存储,Hadoop 将对数据库的依赖降至最低。
  • Hadoop 使用定制的分布式基于文件的存储,这比存储在存储昂贵的数据库中要便宜,例如存储区域网络 ( 存储区域网络 ) 或其他专有存储解决方案。因为数据以文件的形式分布在集群中的机器上,所以它使用多节点复制来提供内置冗余。
  • Hadoop 的核心原则是使用商品基础设施,这是线性可扩展的,以适应无限的数据,而不会降低性能。这意味着每增加一个基础设施,无论是 CPU、内存还是存储,都会带来 100%的可扩展性。这使得使用 Hadoop 的数据存储成本低于传统的数据存储和处理方法。从不同的角度来看,您可以免费完成添加到群集的每 TB 存储空间的处理。
  • Hadoop 通过可编程应用编程接口 ( API ) 访问,实现并行处理,不受并发限制。出于不同的目的,相同的数据可以跨系统处理,或者相同的代码可以跨不同的系统处理。
  • 利用高速同步在集群的多个节点上复制数据,实现了 Hadoop 的容错操作。
  • Hadoop 旨在集成高可用性的关键方面,以便用户始终可以使用和访问数据和基础架构。
  • Hadoop 将代码传递给数据,而不是相反;这被称为数据局部性优化。数据的本地处理和结果在同一个集群节点上的存储可以最大限度地减少网络负载,从而提高整体效率。
  • 为了设计容错应用,添加容错部件所涉及的工作有时会超过解决手头实际数据问题所涉及的工作。这就是 Hadoop 得分高的地方。通过将分布式系统的容错与应用逻辑分离开来,它使应用开发人员能够不用担心编写应用。借助 Hadoop,开发人员不再需要处理低级挑战,如故障处理、资源管理、并发性、数据加载、集群中每个节点上作业的分配和管理。他们只能专注于创建在集群上工作的应用,让框架来应对挑战。

封面下的 Hadoop

Hadoop 由 Hadoop 核心和 Hadoop 子项目组成。Hadoop 的核心本质上是 MapReduce 处理框架和 HDFS 存储系统。

Hadoop 的组件如下图所示:

Hadoop under the covers

典型的 Hadoop 堆栈

以下是 Hadoop 整体部分的描述:

  • Hadoop 通用:这个包括所有支持生态系统的库组件和实用程序。
  • Hadoop 分布式文件系统(HDFS) :这个是一个文件系统,提供高可用性冗余分布式数据访问,用 MapReduce 进行处理。
  • Hadoop MapReduce :这个是一个基于 Java 的软件框架,可以对存储数据的节点集群中的大数据集(HDFS)进行操作。

很少有与 Hadoop 相关的顶级 Apache 项目包括以下系统:

  • AVRO :这是一个数据序列化和反序列化系统。
  • 楚科瓦:这里是一个日志数据采集系统。
  • SQOOP :这个是一个与 RDBMS 集成的结构化数据采集框架。
  • hbase :这个是一个面向列的可扩展分布式数据库,支持数百万行和数百万列使用 HDFS 存储和查询实时结构化数据。
  • Hive:这个是一个结构化的数据存储和一个基于 HDFS 的查询基础设施,主要用于数据的聚合、汇总和查询。
  • 看象人:这个是专门为在分布式集群上执行而编写的机器学习算法库。
  • Pig :这个是一个数据流语言,是专门为了简化 MapReduce 应用的编写而设计的。
  • 城市动物园:这个是一个为分布式应用设计的协调服务。

了解 Hadoop 分布式文件系统

Hadoop 分布式文件系统 ( HDFS )是一个文件系统,使用 MapReduce 为进程提供高可用性冗余数据访问。HDFS 解决了大规模数据存储和处理中的两个主要问题。第一个问题是数据局部性,其中代码实际上是发送到数据在集群中的位置,其中数据已经被分成可管理的块,以便每个块可以被独立处理,并且结果被组合。第二个问题与任何子系统级别(可以是 CPU、网络、存储、内存或应用级别)的容错能力有关,这是由于对商品硬件的依赖,除非另有证明,否则对商品硬件的依赖较小。为了解决这些问题,HDFS 的建筑受到了 GFS 早期领导人的启发。

HDFS 的设计目标

HDFS 建筑的三个主要目标如下:

  • 处理从几千兆字节到几千兆字节的非常大的文件。
  • 流数据处理,以高吞吐率读取数据,并在读取时处理数据。
  • 它可以在没有特殊硬件要求的商用硬件上执行。

HDFS 的作品

HDFS 有两个重要的子系统。一个是名称节点,它是系统维护和管理其他节点中存在的块的主节点。第二个是数据节点,是在名字节点的监督下工作的从节点,部署在每台机器上提供实际存储。这些节点一起为客户端提供读写请求,客户端从这些节点存储和检索数据。如下图所示:

Working of HDFS

作业跟踪器和名称节点

主节点是数据拆分的元数据存储在内存中的地方。该元数据用于在稍后的时间点重建从节点中存储的完整数据,以便作业可以在各个节点上运行。至少在三台机器上复制数据分割(默认复制因子)。当从节点的硬件出现故障时,这很有帮助,并且可以从存储冗余副本的机器上恢复数据,并且在其中一台机器上执行作业。他们共同负责整个集群中数据的存储、复制和管理。

在 Hadoop 集群中,文件系统节点(数据节点)中的数据被复制到集群中的多个节点。这种复制增加了系统在机器或子系统故障时的冗余度;存储在其他机器中的数据将用于继续处理步骤。因为数据和处理在同一个节点上共存,所以只有增加一台新机,并获得额外硬盘驱动器的好处和新 CPU 的计算能力(横向扩展),才能实现线性可扩展性。

应该注意的是,HDFS 不适合低延迟数据访问,也不适合存储许多小文件、多次写入和任意文件修改。

理解 MapReduce

MapReduce 是一个操纵和处理庞大数据集的编程模型;它的起源可以追溯到谷歌,谷歌创建它是为了解决搜索计算的可扩展性。它基于并行和分布式处理的原理,不依赖任何数据库。MapReduce 的灵活性在于它能够处理商品服务器集群中大量数据的分布式计算。Hadoop 和 MapReduce 提供了一个称为数据局部性的工具和一个简单的基于任务的流程管理模型。

了解 MapReduce 的工作原理

MapReduce 主要使用两个组件;一个作业跟踪器,它是一个主守护进程,一个任务跟踪器,它运行在所有从节点中。它是一个从守护进程。如下图所示:

Understanding how MapReduce works

MapReduce 内部

开发人员使用 MapReduce 框架用 Java 编写一个作业并提交给集群的主节点,主节点负责处理作业的所有底层数据。

主节点由一个名为JobTracker 的守护进程组成,该守护进程向从节点分发作业。JobTracker类负责将包含任务的 JAR 文件复制到包含任务跟踪器的节点,这样每个从节点就可以生成一个新的 JVM 来运行任务。将 JAR 复制到从节点将有助于处理从节点的故障。节点故障将导致主节点将任务分配给包含相同 JAR 文件的另一个从节点。这可以在节点故障的情况下保持灵活性。

MapReduce 内部构件

一个 MapReduce 作业有两个功能:

  • 映射函数:A 用户编写一个映射函数,接收键值对作为输入,进行处理,发出键值对列表。
  • Reduce 函数 : 用户编写的 Reduce 函数将接受 Map 函数的输出,即中间键值对的列表。这些值通常被组合成一组较小的值,因此它们被命名为“减少”。每个 reducer 调用的输出可能只有 0 或 1 个输出值。

以下是上图中描述的 MapReduce 框架的其他组件:

  • 合并器:这是优化步骤,可以任意调用。这是一个被指定在映射器端执行类似缩减处理并在中间数据上执行映射器端聚合的功能。这将减少通过网络从映射器传输到缩减器的数据量。
  • 拆分器:这个是用来拆分地图输出的键。该键用于通过将一个键的所有值组合在一个分区中来开发一个分区。有时默认分区可以由散列函数创建。
  • 输出:这个收集映射器和减速器的输出。
  • 作业配置:这是管理 MapReduce 作业的主用户界面,用于指定 Map、Reduce 函数和输入文件。
  • 作业输入:这个指定了一个 MapReduce 作业的输入。

PIG-快速入门

由 PIG MapReduce 简化。它是 Pig 编译器和 Pig 拉丁脚本的组合,后者是一种编程语言,旨在简化用于分析大量数据的分布式应用的开发。我们称整个实体为 PIG。

用 PIG 拉丁脚本编写的高级语言代码编译成 MapReduce Java 代码序列,可以并行化。Pig Latin 推动数据成为任何用它编写的程序背后的主要概念。基于数据流范式,它对要处理的数据流起作用;这些数据由指令传输,指令处理数据。这种编程风格类似于电信号如何流经电路或水流过管道。

这种数据流范式与控制流语言形成鲜明对比,控制流语言处理指令流并操作外部数据。在传统程序中,条件执行、跳转和过程调用会改变要执行的指令流。

Pig 拉丁语中的 Processing 语句由接受输入和输出的运算符组成。输入输出是由包、映射、元组和标量数据表示的结构化数据。Pig 类似于数据流图,其中有向顶点是数据路径,节点是处理数据的运算符(如 FILTER、GROUP 和 JOIN)。在 PIG 拉丁语中,每个语句在所有数据到达后立即执行,这与遇到语句后立即执行的传统程序形成对比。

程序员用一套标准的数据处理 Pig 算子 T7 写代码,比如 T8、T0、T1、T9、T2、T3、T10、T4、T5、T11、T6。然后将这些转换为 MapReduce 作业。PIG 本身不具备运行这些工作的能力。它将这些工作委托给 Hadoop。Hadoop 充当这些 MapReduce 作业的执行引擎。

必须明白,Pig 并不是一种通用的编程语言,它自带所有花哨的功能。例如,它没有控制流或范围分辨率的概念,并且具有最小的变量支持,这是许多开发人员在传统语言中习惯的。使用自定义函数(【UDFS】)可以克服这个限制,这是 Pig 的一个可扩展特性。

为了更深入地了解,您可能需要参考 http://pig.apache.org/docs/r0.11.0/的 Apache 网站来了解复杂的语法、用法和其他语言功能。

了解 PIG 的基本原理。

Pig Latin 设计为数据流语言,解决 MapReduce 的以下局限性:

  • MapReduce 编程模型具有紧密耦合的计算,可分为映射阶段、洗牌阶段和约简阶段。这种限制不适用于不适合这种模式的实际应用和具有不同进程的任务(如连接或 N 相)。很少有其他真实世界的数据管道需要额外的协调代码来组合单独的 MapReduce 阶段,以管理管道阶段之间的中间结果。就新开发人员理解计算的学习曲线而言,这是有代价的。
  • 即使是最简单的操作,如投影、过滤和连接,也必须在 MapReduce 中实现复杂的变通方法。
  • MapReduce 代码很难开发、维护和重用,有时比 Pig 中编写的相应代码复杂得多。
  • 由于实现的复杂性,在 MapReduce 中很难进行优化。

PIG 拉丁带来双重优势。它是一种类似 SQL 的语言,具有声明性风格和过程编程语言的能力(例如具有各种可伸缩性特征的 MapReduce)。

Pig 支持嵌套数据和将复杂数据类型作为表的字段嵌入。嵌套数据模型的支持使数据建模更加直观,因为它比数据库以第一范式建模数据的方式更接近数据存在的真实情况。嵌套数据模型还反映了数据在磁盘上的存储方式,使用户能够更直观地编写自定义 UDF。

Pig 支持创建自定义功能,执行特殊数据处理任务;小 PIG 编程的几乎所有方面都可以被 UDF 扩展。这意味着程序员可以使用EvalFunc方法自定义 Pig 拉丁函数,如分组、过滤和连接。您也可以通过扩展LoadFuncStoreFunc自定义加载/存储功能。第二章数据接收输出模式用实例展示了 Pig 的可扩展性。

Pig 有一个特别的功能,叫做ILLUSTRATE功能,帮助大数据开发人员利用样本数据快速开发代码。样本数据尽可能接近真实数据,充分说明了程序的语义。样本数据随着程序复杂度的增加而自动发展。该系统的样本数据有助于早期发现错误及其来源。

使用 Pig 的另一个优点是不需要像传统的数据库管理系统那样在将数据解析成元组之前执行复杂的数据导入过程。这意味着,如果您有一个数据文件,PIG 拉丁查询可以直接在其上运行,而无需导入它。不导入意味着数据只要能被 Pig 读取为元组,就可以任何格式访问和查询。我们不需要像处理数据库一样导入数据,例如,在查询之前将 CSV 文件导入数据库。但是,您需要提供一个函数来将文件内容解析为元组。

了解 PIG 在企业中的相关性

在当前的企业中,大数据处理周期因其复杂性而备受关注,与传统的数据处理周期有很大不同。从各种数据源收集的数据被加载到目标平台;然后,执行基本级别分析,通过应用于数据的元数据层进行发现。这将导致为内容创建数据结构或模式,以便发现数据的上下文和相关性。一旦应用了数据结构,数据将被集成、转换、聚合并准备好进行分析。这个精简的结构化数据集用于报告和特别分析。该过程的结果是提供对数据和任何相关上下文的洞察(基于处理的业务规则)。Hadoop 在每个阶段都可以作为一个处理和存储框架。

下图显示了典型的大数据处理流程:

Understanding the relevance of Pig in the enterprise

企业中的大数据

根据上图,PIG 的作用如下:

  • 采集阶段中,Pig 用于对接多种来源采集的数据,包括实时系统、近实时系统和面向批量的应用。使用 Pig 的另一种方式是通过知识发现平台处理数据,知识发现平台可以是上游,存储输出的子集,而不是整个数据集。
  • 数据发现阶段使用 Pig,Pig 首先分析大数据,然后进行处理。正是在这个阶段,大数据已经准备好与结构化分析平台或数据仓库集成。发现和分析阶段包括数据的标记、分类和归类,这与主题领域非常相似,并导致数据模型的定义或元数据的创建。这些元数据是通过分析和洞察解读大数据最终价值的关键。
  • Pig 用于的数据处理阶段,在此阶段对数据的上下文进行处理探索非结构化环境下数据的相关性;这种关联将有助于在大数据中应用适当的元数据和主数据。这种处理的最大优点是,它可以在多个上下文中处理相同的数据,然后在每个结果集中找到模式,用于进一步的数据挖掘和数据探索。比如考虑到“冷”这个词,就要根据用法、语义等相关信息,正确确定这个词的语境。这个词可能与天气或一种常见疾病有关。在获得这个单词的正确上下文后,可以对数据应用与天气或常见疾病相关的进一步的主数据。
  • 在处理阶段,通过用元数据、主数据和语义库对大数据进行清理和标准化,Pig 还可以在数据文化之后立即进行数据集成。这是数据链接到企业数据集的地方。有许多技术可以将结构化和非结构化数据集之间的数据与元数据和主数据联系起来。这个过程是将非结构化和原始数据转换和集成为结构化格式的第一个重要步骤。现阶段,Pig 的力量广泛应用于数据转换,通过从昂贵的企业数据仓库中卸载大量低价值的数据和工作负载来扩展现有的企业数据仓库。
  • 由于企业中的处理阶段受到严格的服务级别协议的约束,Pig 的可预测性更强,可以与其他系统集成,因此更适合定期安排数据清理、转换和报告工作负载。

当输入数据没有被清理和规范化时,Pig 得分。它可以很好地处理运行时数据模式未知或不一致的情况。Pig 的过程语言模型和非模态方法在数据访问方面提供了更大的灵活性和效率,因此数据科学家可以在原始数据上构建研究模型来快速测试理论。

Pig 通常用于解决解可以表示为有向无环图 ( Dag )的问题,包括标准关系运算(连接、聚合等)的组合。)的 Pig,并使用定制的处理代码通过 UDF 用 Java 或脚本语言编写。这意味着,如果你有一个非常复杂的任务链,其中每个作业的输出被用作下一个作业的输入,Pig 使链接作业的过程很容易完成。

Pig 在大数据工作负载中非常有用,其中有一个非常大的数据集,这个数据集的处理包括不断添加新的小数据片,这会改变大数据集的状态。Pig 善于结合新到达的数据,所以不会对整个数据进行处理,只会对数据的增量和大数据的结果进行有效处理。Pig 为操作员提供了在合理时间内执行增量数据处理的能力。

除了上面提到的传统用例之外,Pig 还有一个固有的优势,那就是编写和优化代码的开发时间比用 Java MapReduce 编写要少得多。手动优化繁琐时 Pig 是更好的选择。Pig 的可扩展性,通过它可以集成你现有的可执行文件、UDF 和 Pig 拉丁脚本,实现更快的开发周期。

PIG 的工作-概述

本节是一个分析和解释 PIG 的文字来说明 PIG 的语言特征的例子。

点亮 PIG

本部分帮助您快速了解如何通过安装和配置引导 Pig 进入动作模式。

Pig 在 Hadoop 集群中工作的首要前提是保持 Hadoop 版本的兼容性,本质上就是 Pig 0.11.0 和 Hadoop 版本 0.20.X 协同工作。x,0.23.X 和 2.x .这是通过改变 HADOOP_HOME 的目录来实现的。下表显示了 Apache Pig 和 Hadoop 之间的版本兼容性。

下表总结了 PIG 与 Hadoop 的兼容性:

|

ApachePIG 版

|

兼容 Hadoop 版本的

|
| --- | --- |
| 0.12.0 | 0.20.x,1.x,0.23.x,2.x |
| 0.11.0 | 0.20.x,1.x,0.23.x,2.x |
| 0.10.1 | 0.20.x,1.x,0.23.x,2.x |
| 0.10.0 | 0.20、1.0、0.23 |
| 0.9.2 | 0.20, 1.0.0 |
| 0.9.1 | zero point two |
| 0.9.0 | zero point two |
| 0.8.1 | zero point two |
| 0.8.0 | zero point two |
| 0.7.0 | zero point two |
| 0.6.0 | zero point two |
| 0.5.0 | zero point two |
| 0.4.0 | Zero point eight |
| 0.3.0 | Zero point eight |
| 0.2.0 | Zero point eight |
| 0.1.1 | Zero point eight |
| 0.1.0 | Zero point seven |

Pigcore 是用 Java 编写的,跨操作系统工作。执行用户命令的 Pig 的外壳是一个 bash 脚本,需要一个 UNIX 系统。Pig 也可以使用 Cygwin 和 Perl 包在 Windows 上运行。

Java 1.6 也是必须输给 Pig 才能操作。或者,您可以在同一台机器上安装以下内容:Python 2.5、JavaScript 1.7、Ant 1.7 和 JUnit 4.5。Python 和 JavaScript 用于编写定制的 UDF。Ant 和 JUnit 分别用于构建和单元测试。通过将 HADOOP_HOME 设置为指向我们已经安装了 HADOOP 的目录,可以用不同版本的 HADOOP 执行 Pig。如果没有设置 HADOOP_HOME,Pig 默认会在嵌入式版本运行,目前是 Hadoop 1.0.0。

下表总结了安装 Pig 的前提条件(0.9.1 之前我们一直在考虑 Pig 的主要版本):

|

ApachePIG 版

|

先决条件

|
| --- | --- |
| 0.12.0 | Hadoop 0.20.2、020.203、020.204、0.20.205、1.0.0、1.0.1 或 0.23.0、0.23.1 |
| Java 1.6 |
| Cygwin(适用于窗户) |
| Perl (for windows) |
| 0.11.0,0.11.1 | Hadoop 0.20.2、020.203、020.204、0.20.205、1.0.0、1.0.1 或 0.23.0、0.23.1 |
| Java 1.6 |
| Cygwin(适用于窗户) |
| Perl (for windows) |
| 0.10.0,0.10.1 | Hadoop 0.20.2、020.203、020.204、0.20.205、1.0.0、1.0.1 或 0.23.0、0.23.1 |
| Java 1.6 |
| Cygwin(适用于窗户) |
| Perl (for windows) |
| 0.9.2 | Hadoop 0.20.2、0.20.203、0.20.204、0.20.205 或 1.0.0 |
| Java 1.6 |
| Cygwin(适用于窗户) |
| Perl (for windows) |
| 0.9.1 | Hadoop 0.20.2、0.20.203、0.20.204 或 0.20.205 |
| Java 1.6 |
| Cygwin(适用于窗户) |
| Perl (for windows) |

Pigs 通常安装在不属于 Hadoop 集群的机器上。这可以是开发人员的机器,它连接到 Hadoop 集群。这种机器称为网关机或边缘机。

清管器的安装是一个简单的过程。从您最喜欢的发行版站点下载 Pig,无论是 Apache、Cloudera 还是 Hortonworks,并按照特定于此发行版的安装指南中指定的说明进行操作。这些说明通常包括在您选择的目录中解除 tarball 绑定的步骤,以及将唯一需要的配置(即 JAVA_HOME 属性)设置到包含 JAVA 发行版的位置的步骤。

要验证清管器安装是否正确,请尝试命令$ pig -help

Pig 可以以两种模式运行:本地和 MapReduce。

  • The local mode: To run Pig in the local mode, install this mode on a machine where Pig is run using your local File System. The -x local flag is used to denote the local mode ($ pig -x local ...). The result of this command is the Pig shell called Grunt where you can execute command lines and scripts. The local mode is useful when a developer wants to prototype, debug, or use small data to quickly perform a proof of concept locally and then apply the same code on a Hadoop cluster (the MapReduce mode).

    $ pig -x local
    ... - Connecting to ...
    grunt>
    

    下载样本代码

    你可以下载你在http://www.packtpub.com账户购买的所有 Packt 书籍的样本代码文件。如果你是在外地买的这本书,可以访问http://www.packtpub.com/support注册,通过邮件直接把文件发给你。

  • The MapReduce mode: This mode is used when you need to access a Hadoop cluster and run the application on it. This is the default mode and you can specify this mode using the -x flag ($ pig or $ pig -x mapreduce). The result of this command is the Pig shell called Grunt where you can execute commands and scripts.

    $ pig -x mapreduce
    ... - Connecting to ...
    grunt>
    

    您也可以执行下面的代码片段,而不是前面的代码片段:

    $ pig
    ... - Connecting to ...
    grunt>
    

理解 Pig 是在本地和 MapReduce 模式下本地解析、检查、编译和计划的,这一点很重要。在 MapReduce 模式下,作业只能在 Hadoop 集群上执行,而在本地模式下,作业只能在本地机器上执行。这意味着在本地模式下无法证明并行性。

Pig 可以在本地和 MapReduce 模式下交互运行或以批处理模式运行。交互式运行 Pig 意味着在 Grunt shell 上执行每个命令,以批处理模式运行它意味着在 Grunt shell 上执行脚本文件(称为 Pig 脚本)中的命令组合。

下面是交互模式的一个简单示例:

grunt> raw_logs_Jul = LOAD 'NASA_access_logs/Jul/access_log_Jul95' USING ApacheCommonLogLoader AS (jaddr, jlogname, juser, jdt, jmethod, juri, jproto, jstatus, jbytes);

grunt> jgrpd = GROUP raw_logs_Jul BY DayExtractor(jdt);

grunt> DESCRIBE jgrpd;

请注意,在前面的示例中,每个 Pig 表达式都是在 Grunt shell 中指定的。以下是批处理模式执行的示例:

grunt> pigexample.pig

在前面的例子中,Pig 脚本(pigexample.pig)最初是在 Grunt shell 上创建和执行的。Pig 脚本也可以在命令提示符下在 grunt shell 之外执行。以下是如何做到这一点:

$>pig <filename>.pig (mapreduce mode)

您也可以使用下面一行代码来代替前面一行代码:

$>pig –x local <filename>.pig (local mode)

用例

本节涵盖用例的快速介绍。几乎每个基于网络的软件应用都会生成日志数据。应用将所有事件和事件的时间戳记录在日志文件中。这些事件可能包括系统配置更改、访问设备信息、用户活动和访问位置信息、警报、事务信息、错误日志和故障消息。日志中数据的价值是利用大数据处理技术实现的,在整个行业的垂直领域一致使用,了解和跟踪应用或服务行为。这可以通过发现模式、错误或次优用户体验来实现,从而将不可见的日志数据转化为有用的性能洞察。通过提供运营和业务智能的用例,可以在整个企业中利用这些见解。

下面代码列表部分的 PIG 拉丁脚本加载两个月的日志文件,分析日志,找出一个月内每天唯一的点击次数。分析出两个关系:一个是七月,一个是八月。这两种关系在每个月的某一天结合起来产生一个输出,我们可以比较每个月的日访问量(例如 7 月 1 日和 8 月 1 日的访问量)。

代码列表

以下是完整的代码列表:

-- Register the jar file to be able to use the UDFs in it
REGISTER 'your_path_to_piggybank/piggybank.jar';

/* Assign aliases ApacheCommonLogLoader, DayMonExtractor, DayExtractor to the CommonLogLoader and DateExtractor UDFs
*/
DEFINE ApacheCommonLogLoader org.apache.pig.piggybank.storage.apachelog.CommonLogLoader();
DEFINE DayMonExtractor org.apache.pig.piggybank.evaluation.util.apachelogparser.DateExtractor('dd/MMM/yyyy:HH:mm:ss Z','dd-MMM');
DEFINE DayExtractor org.apache.pig.piggybank.evaluation.util.apachelogparser.DateExtractor('dd-MMM','dd');

/* Load July and August logs using the alias ApacheCommonLogLoader into the relations raw_logs_Jul and raw_logs_Aug
*/
raw_logs_Jul = LOAD '/user/cloudera/pdp/datasets/logs/NASA_access_logs/Jul/access_log_Jul95' USING ApacheCommonLogLoader AS (jaddr, jlogname, juser, jdt, jmethod, juri, jproto, jstatus, jbytes);
raw_logs_Aug = LOAD '/user/cloudera/pdp/datasets/logs/NASA_access_logs/Aug/access_log_Aug95' USING ApacheCommonLogLoader AS (aaddr, alogname, auser, adt, amethod, auri, aproto, astatus, abytes);

-- Group the two relations by date
jgrpd = GROUP raw_logs_Jul BY DayMonExtractor(jdt);
DESCRIBE jgrpd;
agrpd = GROUP raw_logs_Aug BY DayMonExtractor(adt);
DESCRIBE agrpd;

-- Count the number of unique visits for each day in July
jcountd = FOREACH jgrpd
{
  juserIP =  raw_logs_Jul.jaddr;
  juniqIPs = DISTINCT juserIP;
  GENERATE FLATTEN(group) AS jdate,COUNT(juniqIPs) AS jcount;
}

-- Count the number of unique visits for each day in August
acountd = FOREACH agrpd
{
  auserIP =  raw_logs_Aug.aaddr;
  auniqIPs = DISTINCT auserIP;
  GENERATE FLATTEN(group) AS adate,COUNT(auniqIPs) AS acount;
}

-- Display the schema of the relations jcountd and acountd
DESCRIBE jcountd;
DESCRIBE acountd;

/* Join the relations containing count of unique visits in July and August where a match is found for the day of the month
*/
joind = JOIN jcountd BY DayExtractor(jdate), acountd BY DayExtractor(adate);

/* Filter by removing the records where the count is less than 2600
*/
filterd = FILTER joind BY jcount > 2600 and acount > 2600;

/* Debugging operator to understand how the data passes through FILTER and gets transformed
*/
ILLUSTRATE filterd;

/* Sort the relation by date, PARALLEL specifies the number of reducers to be 5
*/
srtd = ORDER filterd BY jdate,adate PARALLEL 5;

-- Limit the number of output records to be 5
limitd = LIMIT srtd 5;

/* Store the contents of the relation into a file in the directory unique_hits_by_month on HDFS
*/
STORE limitd into '/user/cloudera/pdp/output/unique_hits_by_month';

数据集

例如,我们将在美国宇航局的网络服务器上使用两个月的网络请求日志。这些日志收集于 1995 年 7 月 1 日至 31 日和 1995 年 8 月 1 日至 31 日。以下是文件中字段的描述:

  • 发起请求的主机名(或互联网地址),例如,下一个代码片段中的 109.172.181.143。
  • 日志名在该数据集中为空,在下一个代码片段中由表示。
  • 用户在该数据集中为空,在下一个代码片段中用表示。
  • 时间戳采用DD/MMM/YYYY HH:MM:SS格式。在下面的代码片段中,时区是-0400,例如[02/Jul/1995:00:12:01 -0400]
  • HTTP 请求用引号给出,例如下一个代码片段中的GET /history/xxx/ HTTP/1.0
  • HTTP 响应回复代码在下一个代码片段中是200

日志文件的片段如下:

109.172.181.143 - - [02/Jul/1995:00:12:01 -0400] "GET /history/xxx/ HTTP/1.0" 200 6545

通过代码了解 PIG

以下部分简要描述了运算符及其用法:

PIG 的延展性

在用例示例中,REGISTER函数是将外部自定义代码合并到 Pig 脚本中的三种方法之一。让我们快速了解一下本节中的另外两个 Pig 可伸缩性特性,以便更好地理解。

  • REGISTER: The UDFs provide one avenue to include the user code. To use the UDF written in Java, Python, JRuby, or Groovy, we use the REGISTER function in the Pig script to register the container (JAR and Python script). To register a Python UDF, you also need to explicitly provide which compiler the Python script will be using. This can be done using Jython.

    在我们的示例中,下面一行注册了 Piggybank JAR:

    REGISTER '/opt/cloudera/parcels/CDH-4.3.0-1.cdh4.3.0.p0.22/lib/pig/piggybank.jar';
    
  • MAPREDUCE: This operator is used to embed MapReduce jobs in Pig scripts. We need to specify the MapReduce container JAR along with the inputs and outputs for the MapReduce program.

    例子如下:

    input = LOAD 'input.txt';
    result = MAPREDUCE 'mapreduceprg.jar' [('other.jar', ...)] STORE input INTO 'inputPath' USING storeFunc LOAD 'outputPath' USING loadFunc AS schema ['params, ... '];
    

    前面的语句使用storeFunc来存储inputPath中名为input的关系;原生mapreduce使用storeFunc读取数据。作为执行mapreduceprg.jar的结果而接收的数据从outputPath加载到使用loadFunc作为模式的名为结果的关系中。

  • STREAM: This allows data to be sent to an external executable for processing as part of a Pig data processing pipeline. You can intermix relational operations, such as grouping and filtering with custom or legacy executables. This is especially useful in cases where the executable has all the custom code, and you may not want to change the code and rewrite it in Pig. The external executable receives its input from a standard input or file, and writes its output either to a standard output or file.

    运算符的语法如下:

    alias = STREAM alias [, alias …] THROUGH {'command' | cmd_alias } [AS schema] ;
    

    其中alias为关系名称,THROUGH为关键字,command为带参数的可执行文件,cmd_alias为使用DEFINE运算符为命令定义的别名,AS为关键字,schema指定模式。

代码中使用的运算符

以下是代码中使用的操作符的描述:

  • DEFINE: The DEFINE statement is used to assign an alias to an external executable or a UDF function. Use this statement if you want to have a crisp name for a function that has a lengthy package name.

    对于一个STREAM命令,DEFINE在将可执行文件传输到 Hadoop 集群的任务节点中起着重要作用。这是使用DEFINE运算符的SHIP子句完成的。这不是我们例子的一部分,将在后面的章节中解释。

    在我们的示例中,我们通过名称ApacheCommonLogLoaderDayMonExtractorDayExtractor为相应的完全限定类名定义别名。

    DEFINE ApacheCommonLogLoader org.apache.pig.piggybank.storage.apachelog.CommonLogLoader();
    
    DEFINE DayMonExtractor org.apache.pig.piggybank.evaluation.util.apachelogparser.DateExtractor('dd/MMM/yyyy:HH:mm:ss Z','dd-MMM');
    
    DEFINE DayExtractor org.apache.pig.piggybank.evaluation.util.apachelogparser.DateExtractor('dd-MMM','dd');
    
  • LOAD: This operator loads data from the file or directory. If a directory name is specified, it loads all the files in the directory into the relation. If Pig is run in the local mode, it searches for the directories on the local File System; while in the MapReduce mode, it searches for the files on HDFS. In our example, the usage is as follows:

    raw_logs_Jul = LOAD 'NASA_access_logs/Jul/access_log_Jul95' USING ApacheCommonLogLoader AS (jaddr, jlogname, juser, jdt, jmethod, juri, jproto, jstatus, jbytes);
    
    raw_logs_Aug = LOAD 'NASA_access_logs/Aug/access_log_Aug95' USING ApacheCommonLogLoader AS (aaddr, alogname, auser, adt, amethod, auri, aproto, astatus, abytes);
    

    tuple raw_logs_Jul的内容如下:

    (163.205.85.3,-,-,13/Jul/1995:08:51:12 -0400,GET,/htbin/cdt_main.pl,HTTP/1.0,200,3585)
    (163.205.85.3,-,-,13/Jul/1995:08:51:12 -0400,GET,/cgi-bin/imagemap/countdown70?287,288,HTTP/1.0,302,85)
    (109.172.181.143,-,-,02/Jul/1995:00:12:01 -0400,GET,/history/xxx/,HTTP/1.0,200,6245)
    

    带球状(如*.txt*.csv等。),您可以读取同一目录中的多个文件(所有文件或可选文件)。在下面的例子中,文件夹JulAug中的文件将作为一个联合加载。

    raw_logs = LOAD 'NASA_access_logs/{Jul,Aug}' USING ApacheCommonLogLoader AS (addr, logname, user, dt, method, uri, proto, status, bytes);
    
  • STORE: The STORE operator has dual purposes, one is to write the results into the File System after completion of the data pipeline processing, and another is to actually commence the execution of the preceding Pig Latin statements. This happens to be an important feature of this language, where logical, physical, and MapReduce plans are created after the script encounters the STORE operator.

    在我们的示例中,以下代码演示了它们的用法:

    DUMP limitd;
    STORE limitd INTO 'unique_hits_by_month';
    
  • DUMP: The DUMP operator is almost similar to the STORE operator, but it is used specially to display results on the command prompt rather than storing it in a File System like the STORE operator. DUMP behaves in exactly the same way as STORE, where the Pig Latin statements actually begin execution after encountering the DUMP operator. This operator is specifically targeted for the interactive execution of statements and viewing the output in real time.

    在我们的示例中,以下代码演示了DUMP运算符的使用:

    DUMP limitd;
    
  • UNION: The UNION operator merges the contents of more than one relation without preserving the order of tuples as the relations involved are treated as unordered bags.

    在我们的示例中,我们将使用UNION将两个关系raw_logs_Julraw_logs_Aug组合成一个名为combined_raw_logs的关系。

    combined_raw_logs = UNION raw_logs_Jul, raw_logs_Aug;
    

    tuple combined_raw_logs的内容如下:

    (163.205.85.3,-,-,13/Jul/1995:08:51:12 -0400,GET,/htbin/cdt_main.pl,HTTP/1.0,200,3585)
    (163.205.85.3,-,-,13/Jul/1995:08:51:12 -0400,GET,/cgi-bin/imagemap/countdown70?287,288,HTTP/1.0,302,85)
    (198.4.83.138,-,-,08/Aug/1995:22:25:28 -0400,GET,/shuttle/missions/sts-69/mission-sts-69.html,HTTP/1.0,200,11264)
    
  • SAMPLE: The SAMPLE operator is useful when you want to work on a very small subset of data to quickly test if the data flow processing is giving you correct results. This statement provides a random data sample picked from the entire population using an arbitrary sample size. The sample size is passed as a parameter. As the SAMPLE operator internally uses a probability-based algorithm, it is not guaranteed to return the same number of rows or tuples every time SAMPLE is used.

    在我们的示例中,SAMPLE运算符最多返回 1%的数据用于说明。

    sample_combined_raw_logs = SAMPLE combined_raw_logs 0.01;
    

    tuple sample_combined_raw_logs的内容如下:

    (163.205.2.43,-,-,17/Jul/1995:13:30:34 -0400,GET,/ksc.html,HTTP/1.0,200,7071)
    (204.97.74.34,-,-,27/Aug/1995:12:07:37 -0400,GET,/shuttle/missions/sts-69/liftoff.html,HTTP/1.0,304,0)
    (128.217.61.98,-,-,21/Aug/1995:08:59:26 -0400,GET,/images/ksclogo-medium.gif,HTTP/1.0,200,5866)
    
  • GROUP: The GROUP operator is used to group all records with the same value into a bag. This operator creates a nested structure of output tuples.

    我们的示例中的以下代码片段说明了如何按月对日志进行分组。

    jgrpd = GROUP raw_logs_Jul BY DayMonExtractor(jdt);
    DESCRIBE jgrpd;
    

    jgrpd 的模式内容:下面的输出显示了关系jgrpd的模式,我们可以看到它创建了一个嵌套结构,有两个字段、键和一个用于收集记录的包。键名为groupvalue是与raw_logs_Julraw_logs_Aug组合的别名。在这个例子中。

    jgrpd: {group: chararray,raw_logs_Jul: {(jaddr: bytearray,jlogname: bytearray,juser: bytearray,jdt: bytearray,jmethod: bytearray,juri: bytearray,jproto: bytearray,jstatus: bytearray,jbytes: bytearray)}}
    
    agrpd = GROUP raw_logs_Aug BY DayExtractor(adt);
    DESCRIBE agrpd;
    
    agrpd: {group: chararray,raw_logs_Aug: {(aaddr: bytearray,alogname: bytearray,auser: bytearray,adt: bytearray,amethod: bytearray,auri: bytearray,aproto: bytearray,astatus: bytearray,abytes: bytearray)}}
    
  • FOREACH: The FOREACH operator is also known as a projection. It applies a set of expressions to each record in the bag, similar to applying an expression on every row of a table. The result of this operator is another relation.

    在我们的示例中,FOREACH用于迭代组中的每个数据包记录,以获得不同 IP 地址的计数。

    jcountd = FOREACH jgrpd
    {
      juserIP =  raw_logs_Jul.jaddr;
      juniqIPs = DISTINCT juserIP;
      GENERATE FLATTEN(group) AS jdate,COUNT(juniqIPs) AS }
    
    acountd = FOREACH agrpd
    {
      auserIP =  raw_logs_Aug.aaddr;
      auniqIPs = DISTINCT auserIP;
      GENERATE FLATTEN(group) AS adate,COUNT(auniqIPs) AS acount;
    }
    

    元组的内容:下面的输出显示了关系jcountdacountd中的元组。第一个字段是 DD-MMM 格式的日期,第二个字段是不同点击的次数。

     jcountd
    (01-Jul,4230)
    (02-Jul,4774)
    (03-Jul,7264)
    
     acountd
    (01-Aug,2577)
    (03-Aug,2588)
    (04-Aug,4254)
    
  • DISTINCT: The DISTINCT operator removes duplicate records in a relation. DISTINCT should not be used where you need to preserve the order of the contents.

    下面的示例代码演示了使用DISTINCT删除重复的 IP 地址,以及使用FLATTEN删除jgrpdagrpd的嵌套。

    jcountd = FOREACH jgrpd
    {
      juserIP =  raw_logs_Jul.jaddr;
      juniqIPs = DISTINCT juserIP;
      GENERATE FLATTEN(group) AS jdate,COUNT(juniqIPs) AS jcount;
    }
    acountd = FOREACH agrpd
    {
      auserIP =  raw_logs_Aug.aaddr;
      auniqIPs = DISTINCT auserIP;
      GENERATE FLATTEN(group) AS adate,COUNT(auniqIPs) AS acount;
    }
    DESCRIBE jcountd;
    DESCRIBE acountd;
    

    元组的内容:下面的输出显示了jcountdacountd之间关系的模式。我们可以看到 T2 创造的巢穴现在已经被移走了。

    jcountd: {jdate: chararray,jcount: long}
    acountd: {adate: chararray,acount: long}
    
  • JOIN: The JOIN operator joins more than one relation based on shared keys.

    在我们的例子中,我们在一个月的某一天连接两个关系;它返回当月所有日期匹配的记录。没有找到匹配的记录将被删除。

    joind = JOIN jcountd BY jdate, acountd BY adate;
    

    元组的内容:以下输出显示JOIN执行后的结果值。此关系返回当月所有日期匹配的记录;没有找到匹配的记录将被删除。比如我们可以在FOREACH的样本输出中看到jcountd显示2-Jul被点击了 4774 次,acountd没有2-Aug的记录。因此,在JOIN之后,由于没有找到2-Aug的匹配,所以省略了命中2-Jul的元组。

    (01-Jul,4230,01-Aug,2577)
    (03-Jul,7264,03-Aug,2588)
    (04-Jul,5806,04-Aug,4254)
    (05-Jul,7144,05-Aug,2566))
    
  • DESCRIBE: The DESCRIBE operator is a diagnostic operator in Pig and is used to view and understand the schema of an alias or a relation. This is a kind of command line log, which enables us to understand how preceding operators in the data pipeline are changing the data. The output of the DESCRIBE operator is the description of the schema.

    在我们的例子中,我们使用DESCRIBE来理解模式。

    DESCRIBE joind;
    

    输出如下:

    joind: {jcountd::jdate: chararray,jcountd::jcount: long,acountd::adate: chararray,acountd::acount: long}
    
  • FILTER: The FILTER operator allows you to select or filter out the records from a relation based on a condition. This operator works on tuples or rows of data.

    以下示例过滤计数大于 2,600 的记录:

    filterd = FILTER joind BY jcount > 2600 and acount > 2600;
    

    过滤元组的内容:过滤掉所有小于 2600 的记录。

    (04-Jul,5806,04-Aug,4254)
    (07-Jul,6951,07-Aug,4062)
    (08-Jul,3064,08-Aug,4252)
    
  • ILLUSTRATE: The ILLUSTRATE operator is the debugger's best friend, and it is used to understand how data passes through the Pig Latin statements and gets transformed. This operator enables us to create good test data in order to test our programs on datasets, which are a sample representing the flow of statements.

    ILLUSTRATE内部使用一种算法,该算法使用整个输入数据的小样本,并通过 Pig 拉丁脚本中的所有语句传播数据。当遇到像FILTER这样的运算符时,算法智能生成样本数据,运算符可以从数据中删除行,导致 Pig 语句后没有数据。

    在我们的示例中,使用了ILLUSTRATE运算符,如以下代码片段所示:

    filterd = FILTER joind BY jcount > 2600 and acount > 2600;
    ILLUSTRATE filterd;
    

    我们使用的数据集没有计数小于 2600 的记录。ILLUSTRATE已进行两次计数的记录,以确保过滤掉低于 2600 的值。该记录通过了FILTER条件并被过滤掉,因此过滤后的关系中不显示任何值。

    以下屏幕截图显示了输出:

    Operators used in code

    图形输出

  • ORDER BY : ORDERBY运算符用于对指定排序关键字的关系进行排序。到目前为止,Pig 支持对简单类型的字段进行排序,而不是复杂类型或表达式。在下面的示例中,我们基于两个字段(7 月日期和 8 月日期)进行排序。

    srtd = ORDER filterd BY jdate,adate PARALLEL 5;
    
  • PARALLEL : PARALLEL操作员通过指定减速器的数量来控制减速侧的平行度。在本地模式下运行时,默认值为 1。本条款适用于强制降相的操作人员,如ORDERDISTINCTLIMITJOINGROUPCOGROUPCROSS

  • LIMIT: The LIMIT operator is used to set an upper limit on the number of output records generated. The output is determined randomly and there is no guarantee if the output will be the same if the LIMIT operator is executed consequently. To request a particular group of rows, you may consider using the ORDER operator, immediately followed by the LIMIT operator.

    在我们的示例中,运算符返回五条记录作为示例:

    limitd = LIMIT srtd 5;
    

    limitd元组的内容如下:

    (04-Jul,5806,04-Aug,4254)
    (07-Jul,6951,07-Aug,4062)
    (08-Jul,3064,08-Aug,4252)
    (10-Jul,4383,10-Aug,4423)
    (11-Jul,4819,11-Aug,4500)
    
  • FLATTEN : FLATTEN运算符用于通过移除包和元组中的嵌套来展平它们之间的相等关系。FLATTEN的输出和使用示例请参考 distinct 中的示例代码。

解释运算符

在 Hadoop 集群中执行 pig 程序之前,会经历几个阶段,如下图所示,EXPLAIN运算符提供了最好的方式来理解 pig 拉丁代码下发生了什么。EXPLAIN运算符生成一个计划序列,用于将 PIG 拉丁脚本转换为 MapReduce JAR。

使用-dot选项生成程序的图形,该运算符的输出可以转换为图形格式。这将输出写入一个包含解释脚本执行的图表的 DOT 文件。

语法如下:

pig -x mapreduce -e 'pigexample.pig' -dot -out <filename> or <directoryname>

接下来是一个用法示例。如果我们在-out之后指定一个文件名目录,那么所有三个输出文件(逻辑、物理和 MapReduce 计划文件)都会在这个目录下创建。在下一种情况下,所有文件都将在pigexample_output目录下创建。

pig -x mapreduce -e ' pigexample.pig' -dot -out pigexample_output

根据给定的步骤将 DOT 文件转换为图像格式:

  1. 在您的机器上安装 graphviz。

  2. 通过执行以下命令来绘制用点语言编写的图形:

    dot –Tpng filename.dot  >  filename.png
    

下图显示了 PIG 加工的每个步骤:

The EXPLAIN operator

PIG 拉丁文到 Hadoop JAR

  • 查询解析器😗* 解析器使用另一种语言识别工具 ( Antlr ) 语言解析器验证程序语法是否正确,所有变量是否定义正确。解析器还检查模式的类型正确性,并生成中间表示, 抽象语法树 ( AST )。**

  • The logical plan: The intermediate representation, AST, is transformed into a logical plan. This plan is implemented internally as a directed graph with all the operators in the Pig Latin script mapped to the logical operators. The following diagram illustrates this plan:

    The EXPLAIN operator

    逻辑计划

  • 逻辑优化:检查生成的逻辑方案是否有优化机会,如过滤投影下推、列剪枝等。这些取决于剧本。执行优化,然后将计划编译成一系列物理计划。

  • The physical plan: The physical plan is a physical description of the computation that creates a usable pipeline, which is independent of MapReduce. We could use this pipeline and target other processing frameworks such as Dryad. The opportunities for optimizations in this stage are in memory aggregations instead of using combiners. The physical planning stage is also the right place where the plan is examined for the purpose of reducing the number of reducers.

    为了清楚起见,每个逻辑运算符都显示有一个标识符。逻辑运算符转换生成的物理运算符以相同的标识显示。在大多数情况下,每个逻辑运算符都会变成相应的物理运算符。逻辑GROUP运算符被映射成一系列物理运算符:局部和全局重排和打包。像 MapReduce 的Partitioner类和Reducer步骤一样,重排是通过一个键来排序的。

    下图显示了逻辑计划转换为物理计划的示例:

    The EXPLAIN operator

    逻辑到物理计划

  • MapReduce plan: This is the phase where the physical plan is converted into a graph of actual MapReduce jobs with all the inputs and outputs specified. Opportunities for optimization in the MapReduce phase are examined to see if it is possible to combine multiple MapReduce jobs into one job for reducing the data flow between Mappers and Reducers. The idea of decoupling the Logical and Physical plans from the MapReduce plan is to divorce them from the details of running on Hadoop. This level of abstraction is necessary to port the application to a different processing framework like Dryad.

    对于我们的运行示例,以下物理到映射的缩减计划显示了物理操作符在 Hadoop 阶段的分配(仅显示了映射和缩减阶段)。在 MapReduce 计划中,局部重排运算符用输入流的键和标识符解释元组。

    The EXPLAIN operator

    MapReduce 计划的物理学

了解 PIG 的数据模型。

PIG 数据模型由原始类型和复杂类型组成。以下各节简要概述了这些数据类型:

原始类型

PIG 支持Int``Float``Long``DoubleT4 等原始数据类型。

复合型

下面是复杂数据类型,是原始数据类型的组合:

  • 原子:一个原子包含一个值,可以由任何一种原始数据类型组成。

  • 元组:一个元组就像一个行表,或者关系数据库管理系统中的一个字段序列。每个字段可以是任何数据类型,包括基本类型和复杂类型。用括号括起来,()。示例:

     (163.205.85.3,-,-,13/Jul/1995:08:51:12 -0400,GET,/htbin/cdt_main.pl,HTTP/1.0,200,3585)
    
  • : A 包类似于一组表和元组,元组可能重复。Bag 是 Pig 唯一可以溢出的数据结构,这意味着当整个结构不适合内存时,它会溢出到磁盘,必要时会被分页。在包中,元组的模式是灵活的,不需要有相同数量和类型的字段。由包花括号{}中的数据或元组表示。示例:

    {(163.205.85.3,-,-,13/Jul/1995:08:51:12 -0400,GET,/htbin/cdt_main.pl,HTTP/1.0,200,3585)
    (100.305.185.30,-,-,13/AUG/1995:09:51:12 -0400,GET,/htbin/cdt_main.pl,HTTP/1.0,200,3585)}
    
  • 地图:这个是一个关键值数据结构。地图中数据项的模式没有严格执行,提供了采取任何形式的选项。Map 对于原型数据集非常有用,因为原型数据集的模式可能会随着时间的推移而改变。将地图用方括号括起来[]

图式的关联性

PIG 有一种特殊的方法来处理已知和未知的模式。模式的存在是通过命名字段并将其分类为数据类型来赋予字段身份。 Pig 可以通过对数据类型做出适当的假设,在运行时发现模式。如果没有分配数据类型,Pig 会将类型默认为 bytearray,然后根据使用数据的上下文执行转换。当您想要将 Pig 用于研究目的并在未知模式数据上创建快速原型时,该功能将为 Pig 带来优势。虽然使用未指定的模式有这些优点,但建议尽可能多地指定模式,以便在分析过程中更有效地检查和执行。然而,在使用各种运算符时,Pig 处理未知模式的方式有一些特殊之处。

对于执行JOINGROUPUNIONCROSS的关系运算符,如果关系中有任何运算符没有指定模式,则结果关系为空。同样,当您试图展平一个具有未知模式的包时,结果将为空。

展开关于如何在 Pig 中生成空值的讨论。如前一节所述,还有其他几种通过特定运算符的交互来生成空值的方法。快速解释一下,如果比较运算符中的任何子表达式操作数,如==<>MATCHES为空,结果将为空。算术运算符(如+、-、*/)和CONCAT运算符也是如此。记住各种函数如何处理 null 之间的细微差别是很重要的。当AVGMAXMINSUMCOUNT函数忽略空值时,COUNT_STAR函数不会忽略它们,而是像有值一样计算空值。

总结

在这一章中,我们讲述了一系列的想法。中心主题是把你的注意力集中在 PIG 身上,然后探索它的外围。从 Pig 的角度,我们了解什么是设计模式,以及它们是如何被发现和应用的。我们探索了什么是 Hadoop,但我们从历史企业背景的角度进行了探索,发现了 Hadoop 是如何通过迎接传统架构的挑战来改写分布式计算的历史。

我们直观地了解了 Pig 是如何引入一种全新的 Hadoop 编程方法的,也能理解它相对于其他编程方法的优势。此外,它还为我们提供了一个用类似脚本的语言编写代码的工具,对于那些已经知道脚本或者不想用 Java MapReduce 编写代码的人来说,这很容易。通过一组小函数和运算符,它为我们提供了快速处理大量数据的能力。我们用一个代码例子来理解 Pig 的内部结构。这一节的重点是尽可能涵盖更多的领域,不要对 PIG 的探索太深入,给大家一个现成的计算器来了解 PIG。

在下一章中,我们将把对在企业中使用 Pig 的一般概念的理解扩展到具体的用例,在这些用例中,Pig 可以用于各种来源的数据输入和输出。我们将从进入企业的所有数据及其使用方式的循环视图开始,然后我们将扩展到更仔细地查看特定类型的数据,并将我们的模式应用于它。这些分支处理非结构化、结构化和半结构化数据。在每个分支中,我们将学习如何将模式应用于处理多个方面和属性的每个分支。

二、数据接收和输出模式

在前一章中,您已经了解了设计模式的高级概念,并看到了 Pig 是如何实现它们的。我们讨论了 Hadoop 和 Pig 的发展,传统系统的局限性,以及 Hadoop 和 Pig 如何与企业相关,以解决与大数据相关的具体问题。用一个现成的例子来解释 Pig 编程语言,说明了语言的特点。

我们将很快看到使用 Pig 设计模式在 Hadoop 中接收和输出各种数据的能力。本章的总体目标是作为 Hadoop 从业者的发射台,快速加载数据,尽快开始处理和分析数据,然后输出到其他系统,而不会陷入编写复杂 MapReduce 代码的迷宫。

首先,本章总结了大数据环境中常见的各种类型的数据及其来源。然后,我们讨论了几种将存储在各种源系统中的多结构数据导入 Hadoop 的数据入口设计模式。我们还将讨论将存储在 Hadoop 中的数据以本机格式导出到目标系统的数据导出设计模式。为了解释接收和输出模式,我们考虑了各种数据格式,如日志文件、图像、CSV、JSON 和 XML。用来说明这些模式的数据源是文件系统、大型机和 NoSQL 数据库。

数据接收和输出的上下文

数据摄取 是将数据输入系统进行后处理或存储的过程。这个过程包括连接到数据源,访问数据,然后将数据导入 Hadoop。导入意味着将外部来源的数据复制到 Hadoop 中,并将其存储在 HDFS。

数据导出是将数据处理后送出 Hadoop 环境的过程。输出数据的格式将与目标系统的格式相匹配。当下游系统使用数据来创建可视化、服务网络应用或网络服务或执行定制处理时,数据输出被执行。

随着 Hadoop 的出现,我们见证了以前所未有的规模快速高效地接收和输出数据的能力。企业正在根据其分析价值的需要,采用更新的示例来接收和输出数据。每一个输入企业的数据都有潜在的价值。这些提要主要由遗留企业数据、非结构化数据和外部数据组成。数据接收过程处理所有类型的提要,这些提要定期与现有的企业资产同步。数据导出处理限制出站数据,以满足集成下游系统的数据要求。

一旦数据在企业范围内,其对原始数据本身进行有意义分析的能力将得到增强,甚至在它转化为传统意义上更结构化的东西(即信息)之前。我们不再需要高度组织和结构化数据来从中收集见解。然而,随着新的老化算法的激增,任何类型或形式的数据都可以被分析。这最近导致了一种令人兴奋的商业模式,在这种模式下,企业突然发现自己正在从出于合规目的而存储多年的磁带中解压缩数据,以便发现隐藏的宝藏和价值。企业开始意识到,没有任何数据是可有可无或无用的,无论它看起来多么非结构化或无关紧要。他们已经开始争夺每一个可能给他们带来行业竞争优势的数据。

人们又对非结构化数据产生了兴趣:能否与企业现有的结构化数据源进行集成,这种集成能否通过预测性分析带来更好的业务结果。今天的数据科学家陶醉于异质性。探索非结构化数据是他们的新挑战,从随机分布中发现模式是新常态。在选定的云提供商上旋转几个 Hadoop 节点、导入数据和运行复杂的算法已经成为许多数据科学家的日常琐事。这使得处理来自许多不同来源的大量不同类型的数据变得相对简单。所有这些都强调了数据访问各种来源的重要性,这是最终价值的基础。本章我们将讨论如何通过 PIG 的设计模式摄取和排出,并给予特殊的推动力

企业中的数据类型

下节详细介绍了以企业为中心的数据视图及其与大数据处理栈的关联,如下图所示:

Types of data in the enterprise

企业中的数据多样性

以下是大量数据的各种类别的解释:

  • 遗留数据:此数据类型包括来自所有遗留系统和应用的数据,包括在线或离线存储的结构化和半结构化数据格式。数据类型有许多用例——地震数据、飓风数据、人口普查数据、城市规划数据和社会经济数据。这些类型可以被吸收到 Hadoop 中,并与主数据相结合,以创建有趣且具有预测性的混搭。
  • 事务性(OLTP)数据:来自事务性系统的数据传统上加载到数据仓库中。Hadoop 的出现解决了传统系统缺乏极致扩展性的问题。因此,事务性数据通常会被建模,以便在分析中不使用来自源系统的所有数据。Hadoop 可用于加载和分析整个 OLTP 数据,作为预处理或二次处理步骤。它还可以用来接收、输出和集成来自企业资源规划、大型机、供应链管理和客户关系管理系统的交易数据,以创建强大的数据产品。
  • 非结构化数据:这种数据类型包括驻留在企业内容管理平台中的文档、笔记、备忘录和合同。这些企业系统旨在生产和存储内容,而无需大量的数据分析。Hadoop 通过发现基于上下文和用户定义的规则,为接收和处理内容提供了一个接口。内容处理的输出用于定义和设计分析,以探索使用语义技术来挖掘非结构化数据。
  • 视频:很多企业已经开始使用基于视频的数据,获取安全监控、天气、媒体等相关用例的关键洞察。Hadoop 支持捕获视频中的组件,如内容、音频和相关元数据。在 Hadoop 企业数据仓库 ( EDW )中,将上下文化视频数据及关联元数据与结构化数据进行集成,进一步用先进的算法对数据进行处理。
  • 音频:来自呼叫中心的数据包含了很多关于客户、比赛等类别的信息。虽然目前的数据仓库在处理和集成这种类型的数据方面有局限性,但 Hadoop 通过将其与仓库中现有的数据集成,无缝地吸收了这些数据。在 Hadoop 中,音频数据提取可以作为上下文数据和相关元数据进行处理和存储。
  • 影像:静态的影像承载了大量的信息,对于政府机构(地理空间整合)、医疗(x 光和 CAT 扫描)等领域非常有用。在 Hadoop 中吸收这些数据,并将其与数据仓库集成,将通过分析洞察为大型企业带来好处,这将产生商业机会,而这些机会最初由于缺乏数据可用性或处理能力而不存在。
  • 数值/图案/图形:此数据类型属于半结构化范畴。它包括地震数据、传感器数据、天气数据、股市数据、科学数据、射频识别、Hive 塔数据、车载计算机芯片、全球定位系统数据和流媒体视频。其他此类数据是出现的模式,或以周期性间隔重复列表的数字数据或图表。Hadoop 通过将结果与数据仓库相集成来帮助接收和处理这种类型的数据。这种处理将提供分析机会来执行相关性分析、聚类分析或贝叶斯类型分析,这将有助于识别收入泄漏、客户细分行为和业务风险建模中的机会。
  • 社交媒体数据 : 通常归类为脸书、LinkedIn 或 Twitter 数据,社交媒体数据不止这些渠道。这些数据可以从第三方聚合商处购买,如 DataSift、Gnip 和 Nielsen。在 Hadoop 中取这些类型的数据,并与结构化数据相结合,可以实现情感检测等各种社交网络分析应用。

在接下来的章节中,我们将研究大量用于处理上述数据类型的接收和输出模式。

多结构数据的接收输出方式

以下部分描述了接收非结构化数据(图像)和半结构化文本数据(Apache 日志和自定义日志)的具体设计模式。以下是该格式的简要概述:

  • Apache 日志格式:从该格式中提取信息是一个广泛使用的企业用例,并且是综合关联的。
  • 自定义日志格式:此格式代表任何可以用正则表达式解析的日志。理解这种模式将有助于您将其扩展到许多其他需要编写定制加载器的类似用例中。
  • 图像格式:这个是处理非文本数据的唯一模式,描述拍摄图像的模式可以调整,适用于任何类型的二进制数据。我们还将讨论图像输出模式,以说明使用 Pig 的可扩展性输出二进制数据的简单性。

摄入原木时的注意事项

日志存储取决于用例的特性。通常,在企业中,日志被存储、索引、处理并用于分析。MapReduce 的作用是索引和处理摄取的日志数据。处理后,必须存储在为日志索引实时查询提供读取性能的系统中。在本节中,我们将研究存储日志数据的各种选项,以提高实时读取性能:

  • 一种选择是各种基于 SQL 的关系数据库。它们不适合为需要实时查询以获得洞察力的用例存储大量日志数据。
  • 由于以下特点,NoSQL 数据库似乎是存储非结构化数据的好选择:
    • 文档(如 CouchDB 和 MongoDB)将数据存储在文档中,其中每个文档可以包含可变数量的字段或模式。在日志处理的情况下,模式通常是预先确定的,不会如此频繁地改变。因此,文档数据库可以用在模式灵活性(具有不同模式的日志)是主要标准的用例中。
    • 面向列的数据库,如 HBase 和 Cassandra,将密切相关的数据存储在列中,这是可扩展的。这些数据库非常适合分布式存储,并且注重性能。这些在读取操作和计算一组列时非常有效。然而,与此同时,这些数据库不如其他 NoSQL 数据库灵活。在存储数据之前,必须事先确定数据库结构。日志文件处理的最常见用例可以在面向列的数据库中实现。
    • GraphLab 和 Secondary 等图形数据库是适用于日志文件处理的 Neo4j,因为日志不能表示为图形的节点或顶点。
    • 像 SimpleDB 这样的键值数据库存储可以由键访问的值。当数据库方案灵活且需要频繁访问数据时,键值数据库运行良好。理想情况下,这些数据库不适合在一段时间内模式没有明显变化的日志文件处理。

考虑到上述特点,最好的做法是选择柱状数据库的性能和分发能力,而不是键值模式和文档数据库对日志文件存储和处理的灵活性。帮助做出更好决策的另一个重要标准是选择具有良好读取性能而不是良好写入性能的柱状数据库,因为必须读取和聚合数百万个日志才能进行分析。

根据所有标准,企业已经成功实施了使用 HBase 作为首选数据库的日志分析平台。

Apache 日志摄取模式

日志摄取模式描述了如何使用 pig Latin 将 Apache 日志摄取到 Hadoop 文件系统中,以在数据管道上进一步处理它们。

我们将讨论 Apache 日志与企业的相关性,并了解各种日志格式,每种格式的差异,以及日志结合 Pig 的用例。您还将了解 Pig 如何使摄取这些日志比在 MapReduce 中编程容易得多。

下面关于这个模式的实现级细节的讨论旨在让您熟悉重要的概念和适用的替代方案。一个示例代码片段用于从 Pig 语言的角度更好地理解模式,然后是使用模式的结果。

背景

Apache 服务器日志用于服务器运行状态的一般跟踪和监控。Apache 网络服务器创建 Apache 日志,并将它们存储在本地存储中。这些日志通过 Apache Flume 框架定期移动到 Hadoop 集群中,分布在 Cloudera 等主要 Hadoop 发行版中,以便存储在 Hadoop 文件系统中。

以下是 Flume 的简要介绍:

  • Flume 是一个分布式的、可靠的生产者-消费者系统,用于将大量日志(配置后自动)移动到 Hadoop 进行处理。
  • 接收器代理运行在 web 服务器(生产者)上。
  • 代理使用收集器(使用者)定期收集日志数据。
  • 代理将日志数据推送到目标文件系统 HDFS。

下图描述了此体系结构的快照:

Background

典型测井采集

动机

分析日志数据了解并跟踪任何应用或 web 服务的行为。它包含大量关于应用及其用户的信息,这些信息被聚合以发现模式、错误或次优用户体验,从而将不可见的日志数据转化为有用的性能洞察。这些见解以特定用例的形式在整个企业中使用,从产品支持到工程和营销,提供运营和商业智能。

一个计算机集群包含许多独立的服务器,每个服务器都有自己的日志工具。这使得服务器管理员很难分析整个集群的整体性能。将每台服务器的日志文件合并成一个日志文件对于获取有关群集性能的信息非常有用。组合日志文件可以直观地显示集群的性能,并在短时间内检测集群中的问题。然而,将集群的服务器日志存储几天将产生几千兆字节的数据集。分析如此大量的数据需要大量的处理能力和内存。像 Hadoop 这样的分布式系统最适合这种处理能力和内存。

日志大小可以增长到数百 GB。Hadoop 吸收这些文件进行进一步分析,并考虑各种维度,如时间、源地理和浏览器类型,以提取模式和重要信息。

用例

该设计模式可用于以下用例:

  • 找到链接到网站的用户。
  • 查找网站访问者和独特用户的数量。这可以跨空间和时间维度完成。
  • 在时间和空间上找出峰值负载时间。
  • 分析机器人和蠕虫的访问。
  • 查找与站点性能相关的统计数据。
  • 分析服务器的响应和请求,深刻理解 web 服务器问题的根源。
  • 分析用户对网站的哪个页面或哪个部分更感兴趣。

模式实现

通过使用 piggybank 的ApacheCommonLogLoaderApacheCombinedLogLoader类,在 Pig 中实现了 Apache 访问日志摄取模式。这些功能扩展了 PIG 的LoadFunc水平。

代码片段

以下示例中使用的两种不同类型的日志是名为access_log_Jul95通用日志格式和名为access.log组合日志格式。在企业设置中,这些日志是使用生成日志的 web 服务器上的 Flume 代理提取的。

下表描述了每种类型的组成属性:

|

属性

|

通用日志格式

|

组合日志格式

|
| --- | --- | --- |
| 国际计算机的互联网地址 | 是 | 是 |
| 用户标识 | 是 | 是 |
| 请求时间 | 是 | 是 |
| 请求文本 | 是 | 是 |
| 状态代码 | 是 | 是 |
| 字节大小 | 是 | 是 |
| 参考文献 |   | 是 |
| HTTP 代理 |   | 是 |

Code of common log loader class

以下 Pig 脚本解释了如何使用CommonLogLoader类将access_log_Jul95日志文件摄取到 Pig 关系日志中:

/*
Register the piggybank jar file to be able to use the UDFs in it
*/
REGISTER '/usr/share/pig/contrib/piggybank/java/piggybank.jar';

/*
Assign the aliases ApacheCommonLogLoader and DayExtractor to piggybank's CommonLogLoader and DateExtractor UDFs
*/
DEFINE ApacheCommonLogLoader org.apache.pig.piggybank.storage.apachelog.CommonLogLoader();
DEFINE DayExtractor org.apache.pig.piggybank.evaluation.util.apachelogparser.DateExtractor('yyyy-MM-dd');

/*
Load the logs dataset using the alias ApacheCommonLogLoader into the relation logs
*/
logs = LOAD '/user/cloudera/pdp/datasets/logs/access_log_Jul95' USING ApacheCommonLogLoader
    AS (addr: chararray, logname: chararray, user: chararray, time: chararray,
    method: chararray, uri: chararray, proto: chararray,
    status: int, bytes: int);
/*
* Some processing logic goes here which is deliberately left out to improve readability
*/

/*
Display the contents of the relation logs on the console
*/
DUMP logs;

Code of combined loader class

以下 PIG 脚本解释了如何使用CombinedLogLoader类将access.log文件摄取到 PIG 关系日志中:

/*
Register the piggybank jar file to be able to use the UDFs in it
*/
REGISTER '/usr/share/pig/contrib/piggybank/java/piggybank.jar';

/*
Load the logs dataset using piggybank's CombinedLogLoader into the relation logs
*/
logs = LOAD '/user/cloudera/pdp/datasets/logs/access.log'
  USING org.apache.pig.piggybank.storage.apachelog.CombinedLogLoader()
  AS (addr: chararray, logname: chararray, user: chararray, time: chararray,
    method: chararray, uri: chararray, proto: chararray,
    status: int, bytes: int,
    referer: chararray, useragent: chararray);
/*
* Some processing logic goes here which is deliberately left out to improve readability
*/

-- Display the contents of the relation logs on the console
DUMP logs;

结果

使用这种模式的结果是,来自 Apache 日志文件的数据存储在一个包中。以下是用无效值存储 Pig 关系的几种方法:

  • 如果日志文件包含无效数据,空值将存储在包中。
  • 如果在AS子句之后的模式中没有定义数据类型,那么在包中所有的列都将默认为bytearray。Pig 稍后将根据数据使用的上下文执行转换。有时需要显式键入列,以减少分析时间错误。

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • chapter2/code/
  • chapter2/datasets/

自定义日志摄取模式

用户自定义日志摄取模式描述如何使用 pig Latin 将任意类型的日志摄取到 Hadoop 文件系统中,以进一步处理数据管道上的日志。

我们将讨论定制日志在企业中的相关性,并了解这些日志是如何生成并传输到 Hadoop 集群的,以及日志与 Pig 相结合的用例。您还将了解 Pig 如何使摄取这些日志比在 MapReduce 中编程容易得多。

下面关于这个模式的实现级细节的讨论旨在让您熟悉重要的概念和适用的替代方案。一个示例代码片段用于从 Pig 语言的角度更好地理解模式,然后是使用模式的结果。

背景

大多数日志使用特定的约定来划分组件字段,类似于 CSV 文件,但也有我们遇到文本文件的情况,这些文件没有正确分隔(通过制表符或逗号)。这些日志在分析前需要清理。在到达 HDFS 之前,数据可以通过 Flume、Chukwa 或 Scribe 进行清理,并以 Pig 或 Hive 易于处理的格式进行存储,以便进行分析。如果数据以未清理的格式存储在 HDFS,您可以编写一个 Pig 脚本来清理数据,并将其加载到 Hive 或 HBase 中进行分析,以备后用。

动机

Pig 在处理非结构化数据方面的声誉源于其对具有部分或未知模式的数据的本地支持。加载数据时,可以选择指定模式,也可以指定加载后的模式。这与其他系统(如 Hive)形成鲜明对比,在 Hive 中,您必须在加载之前强制实施模式。

当文本数据尚未标准化和格式化时,使用此模式。

用例

以下是可以应用这种模式的一般用例:

  • 接收任何没有明确定义模式的文本或日志文件。
  • 获取文本或日志文件,并根据分析的适用性实验性地找出可以强加给它们的模式。

模式实现

利用 piggybank 的TextLoader功能,在 Pig 中实现了非结构化文本的摄入模式。这些函数继承了LoadFunc类。

Pig 有一个很好的特性,如果没有显式指定模式,它可以解释数据的类型。在这种情况下,字段被设置为默认的bytearray类型,然后根据下一条语句中数据的用法和上下文推断出正确的类型。

Piggybank 的TextLoader功能可以加载文本文件,将它们拆分成新的行,并将每一行加载到 Piggybank 元组中。如果模式是用AS子句指定的,那么每个元组都被认为是chararray。如果省略号子句没有指定模式,则结果元组将没有该模式。

同样,使用指定的正则表达式模式过滤行后,可以使用MyRegexLoader类加载文件内容。可以使用MyRegExLoader指定正则表达式格式。如果一个模式作为参数传递给它,这个函数返回一个匹配的正则表达式chararray

代码片段

在这个用例中,我们说明了应用日志文件的摄取,并通过分析请求/响应模式来帮助识别 web 服务器中潜在的性能问题。我们将使用sample_log.1数据集来计算每个服务的平均响应时间。日志文件包含嵌入的事件日志以及 web 应用生成的 web 服务请求和响应信息。格式如下面的代码所示。这里,我们只对提取请求-响应对感兴趣,忽略了与 info、DEBUG 和 ERRORS 相关的事件信息:

/* other unstructured event logs related to INFO, DEBUG, and ERROR logs are depicted here */
Request <serviceName> <requestID> <Timestamp>
Response <serviceName> <requestID> <Timestamp>
/* other unstructured event logs related to INFO, DEBUG, and ERROR logs are depicted here */

下面的代码片段显示了使用MyRegexLoader加载与指定正则表达式匹配的行:

/*
Register the piggybank jar file to be able to use the UDFs in it
*/
REGISTER '/usr/share/pig/contrib/piggybank/java/piggybank.jar';

/*
Load the logs dataset using piggybank's MyRegExLoader into the relation logs.
MyRegexLoader loads only the lines that match the specified regex format
*/
logs = LOAD '/user/cloudera/pdp/datasets/logs/sample_log.1'
  USING org.apache.pig.piggybank.storage.MyRegExLoader(
    '(Request|Response)(\\s+\\w+)(\\s+\\d+)(\\s+\\d\\d/\\d\\d/\\d\\d\\s+\\d\\d:\\d\\d:\\d\\d:\\d\\d\\d\\s+CST)')
    AS (type:chararray, service_name:chararray, req_id:chararray, datetime:chararray);

/*
* Some processing logic goes here which is deliberately left out to improve readability
*/

-- Display the contents of the relation logs on the console
DUMP logs;

进一步处理将在提取的日志上完成,以计算每个服务的平均响应时间并识别潜在的性能问题。

以下代码片段显示了使用TextLoader加载自定义日志:

/*
Load the logs dataset using TextLoader into the relation logs
*/
logs = LOAD '/user/cloudera/pdp/datasets/logs/sample_log.1' USING TextLoader  AS (line:chararray);

/*
The lines matching the regular expression are stored in parsed_logs.
FILTER function filters the records that do not match the pattern
*/
parsed_logs = FILTER logs BY $0 MATCHES '(Request|Response)(\\s+\\w+)(\\s+\\d+)(\\s+\\d\\d/\\d\\d/\\d\\d\\s+\\d\\d:\\d\\d:\\d\\d:\\d\\d\\d\\s+CST)';

/*
* Some processing logic goes here which is deliberately left out to improve readability
*/

-- Display the contents of the relation parsed_logs on the console
DUMP parsed_logs;

结果

使用此模式的结果是,日志文件中的数据存储在包中。该袋用于后续分析步骤。

以下是用无效值存储 Pig 关系的几种方法:

  • 如果日志文件包含无效数据,空值将存储在包中。
  • 如果在AS子句之后的模式中没有定义数据类型,那么在包中所有的列都将默认为bytearray。Pig 稍后将根据使用数据的上下文执行转换。有时需要显式键入列,以减少分析时间错误。
    • 您可以在AS子句后定义数据类型,但是在为每列定义适当的数据类型时必须小心。当无法进行数据类型转换时,包中会存储空值,例如chararray类型强制转换为int类型,导致空值。但是int可以铸造成chararray。(例如int 27可以打成chararray "27"。)
  • 您必须特别注意可能导致关系中出现空值的数据。像COUNT这样的关系运算符会忽略空值,但是COUNT_STAR函数不会忽略它,而是将空值视为有价值的值。

附加信息

本节的完整代码和数据集可以在以下 GitHub 目录中找到:

  • chapter2/code/
  • chapter2/datasets/

图像输入和输出模式

本节设计模式描述了如何使用 Pig Latin 在 Hadoop 文件系统中捕获并输出一组图像,以进一步处理数据管道中的图像。

我们将讨论图像在企业中的相关性,并了解创建和存储图像的各种方法,收集要在 Hadoop 上处理的图像的最佳方式,以及将图像与 Pig 相结合的用例。您还将学习 Pig 如何使用用 Java 编写的自定义 UDF 轻松捕获这些图像。

下面关于这个模式的实现级细节的讨论旨在让您熟悉重要的概念和适用的替代方案。一个示例代码片段用于从 Pig 语言的角度更好地理解模式,然后是使用模式的结果。

背景

Hadoop 有许多处理结构化数据和非结构化文本数据的记录用例。然而,我们有证据表明,许多情况下使用 Hadoop 的真正力量来处理其他形式的非结构化数据,如图像、视频和声音文件。

在图像处理方面,Hadoop 在分析气象/军事/民用卫星拍摄的图像时,即当图像尺寸大、分辨率高,需要由一组服务器进行处理时,起到了关键作用。

Hadoop 为大图像或一组小图像提供了有效的存储机制。不同于在 RDBMS 中将图像存储为 BLOB 的过程,无法通过 SQL 进行大规模、有意义的分析,可以在 Hadoop 上编写特定的图像处理算法,可以处理单个图像和一组图像,并行进行高端的图像分析。

动机

这种模式适合在 Hadoop 中加载和处理大量的图像文件。将图像加载到数据管道中是由一个用 Java 编写的 UDF 完成的。

Motivation

图像入口和出口

获取非结构化图像数据,并将其与提供上下文信息的结构化图像元数据(如标签、EXIF 信息和对象标签)相结合,导致社交媒体分析和其他领域(如安全、情报收集、天气预报和人脸识别)的更新和发展。这个想法可以扩展到更广泛的图像特征,使我们能够以革命性的方式检查和分析图像。

图像导入 Hadoop 后,原始图像的实际处理是一项复杂的任务,涉及原始像素级的多次计算。这些计算是由低级的 C 和 C++算法完成的。Hadoop 与这些算法集成,使用 Hadoop 流包装这些算法,并作为标准 Hadoop 作业工作。

图像输出模式试图展示一种简单的机制,其中作为序列文件存在于 HDFS 的二进制图像作为图像文件输出。这种模型的动机在于,基于 Hadoop 的图像处理算法可以对图像进行复杂的计算,以连接其组件来创建更大的图像。

Hadoop 通过将图像文件分组为少量的大文件而不是大量的小图像文件来有效地工作。使用大量小图像文件(其大小小于 64 MB 的 HDFS 块大小)可能会导致从磁盘读取大量数据并搜索名称节点,这可能会导致大量网络流量将这些文件从一个节点传输到另一个节点。这将导致无效的数据访问。这种设计模式探索了一种通过在 Hadoop 中将这些图像文件分组为序列文件来克服这种限制的方法。您可以扩展此模式来接收和处理其他类型的二进制文件,如声音和视频。

拍摄设计模式适用于作为图像文件的大语料库的一部分的图像,其中每个图像都是不同的,将它们组合在一起是不自然的。这种模式不适合在 Hadoop 集群的节点之间划分非常大的映像。上图显示了该架构的示意图。

用例

您可以考虑在以下用例中应用图像捕获模式作为预处理步骤:

  • 捕获多个图像,以对每个图像应用各种类型的图像过滤器。
  • 图像质量的批量增强
  • 理解图像的内容,例如,应用基于人工智能的无监督计算机视觉算法从图像中提取道路、运河或建筑物等特征。
  • 使用图像进行模式匹配,例如医学和地理信息系统图像。

您可以考虑在必须从图像中去除噪声的用例中应用图像导出模式。将原始图像加载到 Hadoop 中并进行处理以去除噪声;通过组合图像的多个块来创建新图像,并且返回被噪声过滤的图像。

模式实现

下一节介绍图像捕捉模式和图像输出模式的模式实现。

影像门户的实现

使用自定义加载器函数在 Pig 中实现图像捕获模式,在 Java 中实现为 UDF 函数。这ImageToSequenceFileUDF将图像转换成序列文件。输入是图像目录的 HDFS 路径,输出是序列文件的路径。

序列文件将图像文件的内容存储为映射到文件名关键字的值。因为序列文件可以拆分,所以可以通过流式传输或使用 MapReduce 进行处理。MapReduce 在内部使用一个标签将文件划分成块大小的块,并独立操作。文件可以被许多编解码器压缩,块压缩用于最大限度地提高存储和检索效率。在这种情况下,将没有解压缩器来防止数据洗牌和带宽消耗。当序列文件中存储大量图像数据时,这将使 Hadoop 的可伸缩优势得以利用。

图像导出的实现

Image 导出模式利用自定义存储功能在 Pig 中实现,在 Java 中实现为 UDF。这个SequenceToImageStorage类将序列文件转换成图像,并将其存储在磁盘上的指定位置。这个函数的输入是序列文件的路径。

代码片段

以下部分描述了图像捕获模式的代码,后面是图像退出。

图像输入

为了解释这种模式是如何工作的,我们考虑一组存储在 HDFS Hadoop 文件系统可访问的文件夹中的图像文件。图像未经预处理;它们以原始格式(JPEG)存储。下面的代码有两个主要部分。首先是 Pig Latin 脚本,它加载包含 images 文件夹路径的文件,其次是用 Java 编写的自定义 UDF,它实际上在幕后工作,将一个图像或一组图像分解成序列文件。

PIG

以下是读取图像文件并将其转换为序列文件的 Pig 脚本:

/*
Register the custom loader imagelibrary.jar, it has UDFs to convert images to sequence file and sequence file to images
*/
REGISTER '/home/cloudera/pdp/jars/imagelibrary.jar';

/*
Load images_input file, it contains the path to images directory
*/
images_file_path = LOAD '/user/cloudera/pdp/datasets/images/images_input' AS (link:chararray);

/*
ImageToSequenceFileUDF converts multiple image files to a sequence file.
This ensures that there are no large number of small files on HDFS, instead multiple small images are converted into a single sequence file.
Another advantage of sequence file is that it is splittable.
The sequence file contains key value pairs, key is the image file name and value is the image binary data.
It returns the path of the sequence file.
*/
convert_to_seq = FOREACH images_file_path GENERATE com.mycustomudf.ImageToSequenceFileUDF();

/*
* Some processing logic goes here which is deliberately left out to improve readability
*/

-- Display the contents of the convert_to_seq on the console
DUMP convert_to_seq;
图像到序列 UDF 片段

以下是ImagetoSequenceFileUDF 的 Java 代码片段,展示了从图像文件到序列文件的转换:

public static String createSequenceFile(Path inPutPath)
{
.
.

for(int i=0;i<status.length;i++)
  {
    //FSDataInputStream is opened at the given path
    dataInputStream = fileSystem.open(status[i].getPath());
    // extracting image name from the absolute path
    fileName = status[i].getPath().toString().
    substring(status[i].getPath().toString().
    lastIndexOf("/")+1);
    byte buffer[] = new byte[dataInputStream.available()];
    //buffer.remaining() bytes will be read into buffer.
    dataInputStream.read(buffer);
    /*Add a key/value pair. Key is the image filename and
      value is the BytesWritable object*/
    seqFileWriter.append(new Text(fileName),
    new BytesWritable(buffer));
    .
    .
  }
}

图像退出

下一节描述图像退出的代码。

PIG

以下是将序列文件的内容输出到图像的 Pig 脚本:

/*
Register the custom jar, it has UDFs to convert images to sequence file and sequence file to images
*/
REGISTER '/home/cloudera/pdp/jars/imagelibrary.jar';

/*
Load images_input file, it contains the path to images directory
*/
images_file_path = LOAD '/user/cloudera/pdp/datasets/images/images_input' AS (link:chararray);

/*
ImageToSequenceFileUDF function converts multiple image files to a sequence file.
This ensures that there are no large number of small files on HDFS, instead multiple small images are converted into a single sequence file.
Another advantage of sequence file is that it is splittable.
The sequence file contains key value pairs, key is the image file name and value is the image binary data.
It returns the path of the sequence file.
*/
convert_to_seq = FOREACH images_file_path GENERATE com.mycustomudf.ImageToSequenceFileUDF();

/*
* Some processing logic goes here which is deliberately left out to improve readability.
* It is assumed that in-between the load and store steps, a user performs some image processing step such as stitching multiple image tiles together.
*/

/*
The custom UDF SequenceToImageStorage reads the sequence file and writes out images.
It reads each key/value pair and writes out the contents as images with keyname as the filename in the folder seq_to_img_output
*/
STORE convert_to_seq INTO '/user/cloudera/pdp/output/images/seq_to_img_output' USING com.mycustomudf.SequenceToImageStorage();
序列对 UDF 进行成像

以下是自定义存储功能SequenceToImageStorage和的片段,用于读取序列文件并将内容写入图像文件:

@Override
public void putNext(Tuple tuples) throws IOException {
  .
  .
  // Do this for each key/value pair
  while (seqFilereader.next(key, value))
  {
    bufferString = value.toString().split(" ");
    buffer =new byte[bufferString.length];
    for(int i=0;i<bufferString.length;i++)
    {
    /*
      String parameter parsed as signed integer in the radix given by the second parameter
      */
      buffer[i] = (byte)
      Integer.parseInt(bufferString[i], 16);
    }
    /*
    output path of the image which is the path specified, key is the image name
    */
    outPutPath=new Path(location+"/"+key);
    // FSDataOutputStream will be created at the given Path.
    seqFileWriter = fileSystem.create(outPutPath);
    // All bytes in array are written to the output stream
    seqFileWriter.write(buffer);
  }
  .
  .
}

Hadoop API 的SequenceFile.Reader类用于读取序列文件,获取键值对。迭代键值对,然后为每个键值对创建一个带有键名的新文件,并将该值作为字节写入文件,从而生成多个图像文件。

结果

作为应用图像捕获模式的结果,图像语料库被 Java UDF 解析成序列文件。然后将每个序列文件分解为 RGB 值,并存储在 PIG 拉丁映射关系中。数据管道的下一阶段使用映射关系来进一步处理序列文件。

作为图像输出模式的结果,存储在 HDFS 的序列文件被转换成图像文件,使得上游图像显示系统可以使用这些图像。

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • chapter2/code/
  • chapter2/datasets/

nosql 数据的导入和导出模式

本节描述了从两种类型的 NoSQL 数据中获取数据的模式。为了说明 Pig 随时支持 NoSQL 数据库的能力及其相关用例,我们选择了 MongoDB 等文档数据库和 HBase 等柱状数据库。

MongoDB 出入口模式

MongoDB 导入导出模式描述了如何使用 Pig 拉丁语将 MongoDB 文档集合的内容存储在 Hadoop 文件系统(Pig 关系)中进行数据处理,然后将处理后的数据写回 MongoDB。

我们将讨论存储在 MongoDB 中的数据与企业之间的相关性,并了解访问 MongoDB 数据的各种方式、接收和输出的动机,以及 MongoDB 数据与 Pig 相结合的用例。您还将学习 Pig 如何比用 Java 编写的 MapReduce 代码更直观地接收和导出这些数据。

下面关于这个模式的实现级细节的讨论旨在让您熟悉重要的概念和适用的替代方案。示例代码片段可以从 Pig 语言的角度更好地理解模式和使用模式的结果。

背景

Godb 是一个 NoSQL 数据库,从头开始设计,以文档集合的形式存储数据,不同于 RDBMS 的行列。由于其广泛的索引功能和使用 JSON 与外部应用的集成,它具有很高的可扩展性,并使文档检索变得容易。MongoDB 非常灵活,可以处理可变模式。(集合中的每个文档不必具有相同的架构。)因为 MongoDB 将数据存储为文档,并且这些文档集合的几乎所有属性都被索引,所以作为处理实时查询的操作存储,它是一个非常有效的解决方案。与 Hadoop 不同,Hadoop 擅长离线批处理和聚合各种来源的数据。

动机

在典型的企业中,MongoDB 和 Hadoop 在某些场景下是集成的。在这些场景中,Hadoop 需要处理比 MongoDB 更极端的数据负载,以聚合数据并促进复杂的分析。

来自 MongoDB 的数据被吸收到 Hadoop 中,并用 MapReduce 作业进行处理。Hadoop 使用 Pig 数据管道将数据与来自其他企业来源的附加数据相结合,以开发多数据聚合解决方案。对 Pig 数据管道中的数据进行处理后,写回 MongoDB 进行具体的分析和查询。这确保了现有应用可以使用从 Hadoop 导出的数据来创建可视化或驱动其他系统。

在许多企业用例中,Hadoop 作为一个中央数据存储库,将数据与不同的数据存储集成在一起。在这种情况下,通过使用 MapReduce 作业,MongoDB 可以用作定期向 Hadoop 提供数据的数据源之一。一旦 MongoDB 数据被吸收到 Hadoop 中,合并后的较大数据集就会被处理,并可用于进一步查询它们。

MongoDB 也是运营数据仓库 ( ODS )之一,连接其他数据仓库和数据仓库。获取分析见解包括从这些连接的数据源移动数据和执行 ETL。PIG 可以有效地用于这一目的。Hadoop 充当 ETL 中枢,从一个存储中提取数据,使用 MapReduce 作业执行各种转换,并将数据加载到另一个存储中。

应该注意的是,与已经加载/传输到 HDFS 的数据相比,直接从外部来源(MongoDB)获取的数据具有非常不同的操作性能特征。

用例

您可能要考虑在以下场景中使用数据导入导出模式,其中 MongoDB 和 Hadoop 的集成将获得丰厚的回报:

  • MongoDB 和 Hadoop 分别处理接近实时和批处理的不同工作负载。在您想要将负载卸载到 Hadoop 进行批处理的用例中,考虑使用门户设计模式,从而释放 MongoDB 中的资源。考虑使用导出设计模式,使 MongoDB 成为从 Hadoop 导出数据并支持实时查询操作的接收器。
  • MongoDB 本身有一个在 MongoDB 数据库上运行的 MapReduce 实现。然而,它比 Hadoop MapReduce 慢,因为它是用 JavaScript 实现的,而且它执行复杂分析的数据类型和库更少。考虑在需要将数据卸载到 Hadoop 的用例中使用门户设计模式,以利用 Hadoop 的库支持、机器学习、ETL 功能和处理规模。考虑使用导出设计模式将数据从 Hadoop 移动到 Mongo DB,并使用 MongoDB 的 MapReduce 实现。
  • MongoDB 支持很少的基本数据聚合函数来生成 SQL 风格的聚合,这就需要更高的学习曲线来理解聚合框架。如果您想使用 Hadoop 执行复杂的聚合任务,请考虑使用门户设计模式。
  • 当存在大量非结构化数据并且需要 MongoDB 进行实时分析时,可以使用这种设计模式。在这种情况下,可以使用导入设计模式将 Hadoop 中摄取的原始数据创建一个结构,并使用导出设计模式将数据导出到 MongoDB 中,以促进 MongoDB 中的优化存储,从而进行实时查询和分析。

模式实现

下图显示了 MongoDB 连接器集成:

Pattern implementation

MongoDB 连接器集成

您可以使用 Hadoop 的 MongoDB 连接器来集成 Hadoop 和 MongoDB。这个连接器有助于将数据从 MongoDB 转移到 Hadoop 生态系统,并允许通过其他编程语言(Hadoop 流)进行访问。连接器与 Pig 的集成如上图所示。

进入实施

Pig 使用 MongoLoader函数将 MongoDB 数据加载到 Pig 的拉丁关系中。使用这个函数,数据直接从数据库加载。Pig 也可以使用BSONLoader功能读取 MongoDB 原生格式(BSON)。

MongoLoader函数可以在非模态模式下工作,无需指定字段名。在这种模式下,记录被解释为包含单个映射(文档)的元组。当您不知道 MongoDB 集合的模式时,这很有用。MongoLoader该功能也可以在模式模式下工作,在该模式下可以指定将 Pig 脚本中的字段与文档中的字段进行映射的字段名。

出口变现

PIG 关系中的数据可以通过两种方式写入 MongoDB。第一种方法是使用BSONStorage函数在.BSON文件中存储一个关系,以后可以导入 MongoDB。这种方法的优点是以 MongoDB 的本地存储格式写入,具有高吞吐量。第二种方法使用 MongoDB 的包装器将连接到数据库,并使用MongoStorage函数将其直接写入数据库。该函数将在元组级别运行,并将它接收的每个元组存储到 MongoDB 中的相应文档中。在写之前,已经映射了 Pig 关系和 MongoDB 文档的模式。使用第二种方法将为您在记录或元组级别写入数据提供极大的灵活性,但它会影响输入/输出速度。

MongoStorage该函数还可以通过在构造函数中指定更新键来更新 MongoDB 中已有的文档集合。如果指定了更新关键字,则对应于该关键字的第一个文档(值)将被 Pig 元组的内容更新。

代码片段

在下面的示例代码中,我们考虑已经驻留在 MongoDB 中的nasdaqDB.store_stock数据的内容。数据集包括 20 世纪 70 年代至 2010 年纳斯达克数据;这包括各种公司的股票跟踪数据以及它们在特定一天的交易量数据中的表现。数据集按照跑马灯符号的字母顺序组织,并作为 JSON 对象存储在 MongoDB 中。

进入码

下面的代码通过将 MongoDB 文档的字段映射到模式中指定的字段,执行连接到 MongoDB、建立连接、加载 MongoDB 本地文件、解析它以及仅检索在MongoLoader构造函数中指定的模式的任务。这个抽象是通过调用MongoLoader函数来实现的。

/*
Register the mongo jar files to be able to use MongoLoader UDF
*/
REGISTER '/home/cloudera/pdp/jars/mongo.jar';
REGISTER '/home/cloudera/pdp/jars/mongo-hadoop-pig.jar';

/*
Load the data using MongoLoader UDF, it connects to MongoDB, loads the native file and parses it to retrieve only the specified schema.
*/
stock_data = LOAD 'mongodb://slave1/nasdaqDB.store_stock' USING com.mongodb.hadoop.pig.MongoLoader('exchange:chararray, stock_symbol:chararray, date:chararray, stock_price_open:float, stock_price_high:float, stock_price_low:float, stock_price_close:float, stock_volume:long, stock_price_adj_close:chararray') AS (exchange,stock_symbol,date,stock_price_open,stock_price_high,stock_price_low,stock_price_close,stock_volume,stock_price_adj_close);

/*
* Some processing logic goes here which is deliberately left out to improve readability
*/

/*
Display the contents of the relation stock_data on the console
*/
DUMP stock_data;

导出代码

以下代码描述了将stock_data pig 中存在的数据写入 MongoDB 文档集合:

/*
Register the mongo jar files and piggybank jar to be able to use the UDFs
*/
REGISTER '/home/cloudera/pdp/jars/mongo.jar';
REGISTER '/home/cloudera/pdp/jars/mongo_hadoop_pig.jar';
REGISTER '/usr/share/pig/contrib/piggybank/java/piggybank.jar';

/*
Assign the alias MongoStorage to MongoStorage class
*/
DEFINE MongoStorage com.mongodb.hadoop.pig.MongoStorage();

/*
Load the contents of files starting with NASDAQ_daily_prices_ into a Pig relation stock_data
*/
stock_data= LOAD '/user/cloudera/pdp/datasets/mongo/NASDAQ_daily_prices/NASDAQ_daily_prices_*' USING org.apache.pig.piggybank.storage.CSVLoader() as (exchange:chararray, stock_symbol:chararray, date:chararray, stock_price_open:chararray, stock_price_high:chararray, stock_price_low:chararray, stock_price_close:chararray, stock_volume:chararray, stock_price_adj_close:chararray);

/*
* Some processing logic goes here which is deliberately left out to improve readability
*/

/*
Store data to MongoDB by specifying the MongoStorage serializer.  The MongoDB URI nasdaqDB.store_stock is the document collection created to hold this data.
*/
STORE stock_data INTO 'mongodb://slave1/nasdaqDB.store_stock' using MongoStorage();

结果

作为在 MongoDB 文档集合上应用摄取设计模式的结果,MongoDB URI 指定的集合的内容被加载到stock_dataPIG 关系中。同样,导出设计模式将stock_dataPIG 关系的内容存储到nasdaqDB.store.stock蒙古文数据库文档集合中。

以下方式具体到MongoLoader的实现,可以用无效值存储 Pig 关系:

  • 如果输入的 MongoDB 文档包含一个未在构造函数模式下映射的字段,MongoLoader函数将在 Pig 关系中存储该字段的空值。
  • 如果 MongoDB 文档不包含构造函数模式中指定的字段,则关系的整行或元组将被设置为 null。
  • 如果 MongoDB 文档字段和指定模式之间存在类型不匹配,则MongoLoader将在 Pig 关系中将该字段设置为空。

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • chapter2/code/
  • chapter2/datasets/

糖化血红蛋白的进出方式

HBase 的导入导出模式描述了如何使用 Pig 拉丁语将 HBase 表的内容摄取到 Pig 关系中,对数据进行进一步处理,再将处理后的数据导出到 HBase。

我们将讨论糖化血红蛋白与企业的相关性,了解糖化血红蛋白数据的各种内部存储和外部访问方式,以及糖化血红蛋白数据结合 Pig 的使用案例。您还将了解 Pig 如何通过提供现成的功能来更轻松地导入和导出 HBase 数据。

下面关于这个模式的实现级细节的讨论旨在让您熟悉重要的概念和适用的替代方案。样例代码片段可以从 Pig 语言的角度更好地理解模式,进而是使用模式的结果。

背景

HBase 是一个面向列的 NoSQL 数据库,其灵感来源于 Google 实现的 Big Table,专门设计用于以灵活的模式存储数据并实时访问。它对于包含数十亿列的数据是线性可伸缩的,并且具有数据压缩和快速访问的内存操作功能。

在 HDFS,糖化血红蛋白数据以定制的优化格式存储在内部,称为索引存储文件。HBase 使用 HDFS 来利用其存储和高可用性功能。由于 HDFS 无法存储数据来执行随机读写,因此 HBase 使用针对随机读写访问优化的二进制格式来克服 HDFS 的限制。在 HDFS 存储 HBase 索引存储文件,非常适合 MapReduce 在不从其他地方导入数据的情况下在上面工作。

逻辑上,HBase 将数据存储在一个嵌套的多维映射抽象中,该抽象具有排序的键值对和与键值相关联的时间戳。时间戳使最新版本的数据能够以有序的顺序存储,以便于搜索。HBase 实现了快速和慢速变化数据的概念,因此可以使用版本来相应地存储它们。多维嵌套映射中的数据是通过使用主键来检索的,主键在 HBase 中称为 rowkey,可用于取消引用所有嵌套数据。

多维映射有两个重要的嵌套结构(实现为映射),称为列族和属于列族的列。列族的架构在存储生命周期中不能更改,而列族中列的架构可以有灵活的架构,每行可以更改一次。这种数据组织本质上适合存储不相关的适合实时访问的非结构化数据(因为一切都在地图中)。

动机

需要将 HBase 表摄取到 Pig 中,有助于用 MapReduce 框架对其进行批处理,达到用例目标。在 PIG 数据管道中处理糖化血红蛋白数据后,有时需要将其存储回糖化血红蛋白中,以便实时访问在糖化血红蛋白上运行的查询。正是在这样的背景下,HBase 数据的导入和导出模式显得尤为诱人。

HBase 中的数据通过 HBase Java 客户端的应用编程接口在本地访问,放入并获取数据。这个应用编程接口非常适合与需要实时查询能力的外部应用集成。但是,API 没有能力执行批处理数据处理来创建数据聚合和复杂的管道来生成分析意见。这种批处理能力伴随着低层次的抽象,如 MapReduce 或 Pig 的高级灵活性。

您可以编写 Java MapReduce 作业来访问存储在 HBase 中的数据并进行处理,但与必须编写 Java 代码来访问 HBase 中的数据相比,Pig 在简单性和简洁优化的代码方面得分很高。

通过 Pig 中的运算符访问存储在 HBase 中的数据,可以对 Pig 数据管道中的数据进行操作,并使用批处理对其进行转换。将 Pig 关系中的数据存储到 HBase 中,使 HBase 能够为应用提供实时查询数据的权利。

由于数据以索引存储文件的形式驻留在 HDFS,因此有必要告诉 Pig 如何以 Pig 能够理解和处理的方式将数据序列化和反序列化为 HBase 格式。Pig 需要清楚地知道如何在列族、HBase 抽象中的列和 Pig 的原生数据类型之间进行转换。该模式说明了如何使用HBaseStorage pig 功能完成向/从 HBase 摄取和导出数据的任务。

与 MongoDB 示例不同,这里我们读取了已经存储在 HDFS 的 HBase 文件。我们不连接到 HBase 服务器,也不通过网络从它们读取数据。

用例

以下是 Pig 从 HBase 接收和输出数据的一个用例:

  • 使用摄取设计模式创建一个数据管道,以集成驻留在 HBase 中的实时数据来执行分析。
  • 使用摄取设计模式访问 HBase 中的数据,以便在 Pig 中为下游系统执行高级数据聚合。Pig 可以作为一个 ETL 中枢来转换 HBase 中的数据,并将其与其他应用的数据集成在一起。
  • 使用导出设计模式将 HDFS 现有平面文件的内容存储到一个 HBase 表中。对于实时查询,这种模式对于在 HBase 中存储复杂数据集成或转换管道的结果也很有用。

模式实现

下面一节介绍 HbA1c 摄入模式的模式实现,后面是 HbA1c 输出。

进入实施

hbase 中的数据可以通过以下两种方式获取:

  • 第一种选择是用并行读取的 MapReduce EXPORT job导出整个表,从而将表的内容导出到 HDFS 序列文件。反序列化程序可以用 Java 或 Pig 编写,以访问序列文件的内容,供以后操作。这个选项有点难以实现,因为我们必须从后端访问 HBase 的内容,然后反序列化文件。此外,这可以一次处理一个表并访问多个表;必须重叠的列表。
  • 第二种选择是实现 HBase 进气设计模式,使用 Pig HBaseStorage的内置加载功能。这是一个连接到 HBase 表并将表的内容直接放入 Pig 关系的简单选项。Pig 负责将 HBase 类型映射到 Pig 类型的反序列化任务和并行导入的 MapReduce 作业。HBaseStorage还有一个优点,就是将数据加载到 Pig 关系中,使用所有列族或者只使用列族的列子集。因为列包含键值类型,所以它们可以按类型转换为 Pig 的映射类型。

出口变现

Pig 使用HBaseStorage功能实现导出设计模式。除了使用STORE子句之外,该模式与摄取模式的实现非常相似。STORE子句向 Pig 编译器传达要从指定的 Pig 关系中提取什么数据,并将其序列化到参数中的 HBase 表中。

下图说明了入口和出口实施选项:

The egress implementation

糖化血红蛋白酶与 PIG 的整合

代码片段

下面的代码示例使用了一个包含零售交易复合样本的数据集。包含 T0、T1、T2、T10、T3、T4、T5、T6 等属性。该数据已存储在 HBase 中,以说明此示例。糖化血红蛋白表hbase://retail_transactions通过 PIG 拉丁的HBaseStorage功能进入。

进入码

下面的代码片段说明了摄入 PIG 的糖化血红蛋白数据之间的关系:

/*
Load data from HBase table retail_transactions, it contains the column families transaction_details, customer_details and product_details.
The : operator is used to access columns in a column family.
First parameter to HBaseStorage is the list of columns and the second parameter is the list of options
The option -loadkey true specifies the rowkey should be loaded as the first item in the tuple, -limit 500 specifies the number of rows to be read from the HBase table
*/
transactions = LOAD 'hbase://retail_transactions'
  USING org.apache.pig.backend.hadoop.hbase.HBaseStorage(
  'transaction_details:transaction_date customer_details:customer_id customer_details:age customer_details:residence_area product_details:product_subclass product_details:product_id product_details:amount product_details:asset product_details:sales_price', '-loadKey true -limit 500')
  AS (id: bytearray, transaction_date: chararray, customer_id: int, age: chararray, residence_area: chararray, product_subclass: int, product_id: long, amount: int, asset: int, sales_price: int);

/*
* Some processing logic goes here which is deliberately left out to improve readability
*/

-- Display the contents of the relation transactions on the console
DUMP transactions;

导出代码

以下代码说明了在 HBase 表中存储 Pig 关系的内容:

/*
Load the transactions dataset using PigStorage into the relation transactions
*/
transactions = LOAD '/user/cloudera/pdp/datasets/hbase/transactions.csv' USING PigStorage( ',' ) AS (
    listing_id: chararray,
    transaction_date: chararray,
    customer_id: int,
    age: chararray,
    residence_area: chararray,
    product_subclass: int,
    product_id: long,
    amount: int,
    asset: int,
    sales_price: int);

/*
* Some processing logic goes here which is deliberately left out to improve readability
*/

/*
Use HBaseStorage to store data from the Pig relation transactions into a HBase table hbase://retail_transactions.
The individual contents of transactions are mapped to three column families transaction_details, product_details and customer_details.
*/
STORE transactions INTO 'hbase://retail_transactions' USING org.apache.pig.backend.hadoop.hbase.HBaseStorage('transaction_details:transaction_date customer_details:customer_id customer_details:age customer_details:residence_area product_details:product_subclass product_details:product_id product_details:amount product_details:asset product_details:sales_price');

结果

由于应用了糖化血红蛋白的数据摄入模式,糖化血红蛋白表中以列族和对应列表示的数据会以 PIG 的关系加载。在这个设计模式中,加载到 Pig 关系中的结果类型根据传递的参数而变化。如果用列族和列标识符(CFName:CName)指定一列,结果类型将是由标量值组成的元组。如果使用列族名和部分列名后跟星号(CFName:CN*)来指定列,则生成的列类型将是列描述符作为键的映射。

需要注意的是,在检索 HBase 中存储的时间序列或基于事件的数据时,不能使用 Pig 获取 HBase 值的时间戳信息。

作为应用 HBase 数据输出模式的结果,pig 关系中的数据存储在 HBase 表中,并映射到相应的列族和相应的列。

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • chapter2/code/
  • chapter2/datasets/

结构化数据的入口和出口模式

下面部分以 Hive 为例,作为我们可以获取结构化数据的来源之一,讨论不同的方法。选择 Hive 来说明结构化数据的摄入模式,因为它是企业中使用最广泛的数据接收器。此外,通过理解这种模式,您可以将其扩展到其他结构化数据。

Hive 的接入方式

Hive 摄取模式描述了如何用 Pig Latin 将数据从 Hive 表摄取和排出到 Hadoop 文件系统,以便在数据管道上进一步处理。

我们将讨论 Hive 和企业之间的相关性,并了解内部存储的各种方式(RCFile、序列文件等)。)和 Hive 数据的外部访问(HQL 和 Pig/MapReduce)。您将探索将 Hive 数据与 Pig 相结合的用例。您还将了解 Pig 如何通过提供现成的函数来更容易地摄取 Hive 数据,然后了解 Hadoop 生态系统的一个组件 HCatalog 的作用,以简化 Pig 和 Hive 表之间的连接和访问机制。

下面关于这个模式的实现级细节的讨论旨在让您熟悉重要的概念和适用的替代方案。一个示例代码片段用于从 Pig 语言的角度更好地理解模式,然后是使用模式的结果。

背景

Hive 让熟悉 SQL 并在 RDBMS 工作过的程序员很容易开发出 Hadoop。Hive 使用 HDFS 作为数据的物理存储,这从逻辑角度给出了表级抽象。Hive 实现了自己的类似 SQL 的方言 HiveQL 来访问和操作数据。HiveQL 提供了 SELECT、GROUP 和 JOIN 等运算符,这些运算符在 Hadoop 集群上执行之前会转换为 MapReduce。

在企业中,Hive 已经被数据仓库、商业智能分析、仪表盘等用例广泛认可。所有这些用例在 Hive 中都有一个公共的数据线程,它已经被清理、正确标记、键入并整齐地组织在表中,因此任何特殊的查询或报告都可以毫不费力地生成。与这种情况形成对比的是,Pig 的用例必须处理来自不同来源的新生成的数据,这种情况令人困惑,没有相关的名称、类别或元数据来解释。因此,Pig 在研究数据本身时的相关性是创建一个快速原型,并在非模态数据的表面随机性中寻找意义。

在 HDFS,Hive 数据的存储是通过将 Hive 表的内容序列化为可以存储在 HDFS 的物理文件来实现的。在 Hive 的上下文中,HDFS 被用来提供高可用性、容错性以及在 Hive 的特定文件上运行 MapReduce 的功能。目前,Hive 支持四种不同的存储文件:纯文本文件、二进制序列文件、ORC 文件和 RC 文件。这些文件格式中的每一种都有自己相关的序列化和反序列化功能,它将存储在 Hive 中的数据的表级抽象转换为存储在 HDFS 的文件。

Hive 将有关物理文件内容的信息存储在 RDBMS 上实现的外部元数据存储中(默认情况下选择 Derby、MySQL)。这个元数据存储包含了所有的信息,比如表、模式、类型、物理文件映射等。每当用户执行数据操作时,他们将首先查询这个元存储来找到数据的位置,然后访问实际的数据。

动机

Hive 以随时可用的格式存储数据,以便进行特别分析和报告。数据摄取模式与 Hive 数据相关,Hive 数据被摄取并与 Pig 数据管道中新到达的数据整合;然后,对来自 Hive 和 Pig 的组合数据进行总结、归纳和转换,以便在高级分析模型中进一步使用。

数据导出模式适用于 Pig 数据管道中已经存在的数据,有一种方法可以直接存储在 Hive 表中。

外部 Hadoop 生态系统组件(如 Pig、HBase 或 MapReduce)可以通过知道在 HDFS 使用哪种存储格式(文本、RCFile 或序列文件)来存储 Hive 数据,以及元存储中的表和模式的元数据信息来访问 Hive 数据。

这个入口和出口设计模式描述了用 Pig 读写 Hive 数据的方法。

与 HBase 类似,我们已经在 HDFS 加载了 Hive 文件。这与 MongoDB 形成对比,在 MongoDB 中,我们直接从外部源而不是 HDFS 读取数据。

用例

Hive 摄入设计模式的主要用例是为 Pig 提供对 Hive 中存储的数据的访问。Pig 使用这些数据的原因如下:

  • 它与其他非结构化来源相集成。
  • 清理并转换组合数据。
  • 使用 Pig 管道中其他数据源的组合进行聚合和汇总。

Hive 导出设计模式的主要用例是提供一种机制,用于在 Hive 表的 Pig 管道中存储转换数据。您可以考虑将这种设计模式用于以下目的:

  • 数据在 Pig 数据管道中与外部数据集成,然后导出到 Hive。
  • 将清理和转换后的数据从 Pig 数据管道导出到 Hive。
  • 将聚合导出到 Hive 或其他下游系统,以便进一步处理或分析。

模式实现

以下部分描述了 Hive 进入模式的模式实现,随后是 Hive 退出:

进入实施

以下是将 Hive 数据加载到 Pig 拉丁关系中的两种方式:

  • 一种方法是显式指定反序列化程序从 Hive 中检索数据。例如HiveColumnarLoader是 Pig 的反序列化器,专用于使用 RCFile 格式加载或序列化到 Hive 中的数据。同样,我们可以使用 Piggybank 的SequenceFileLoader从 Hive 加载已经以SequenceFile格式存储的数据。这两个例子与文件的位置、用于存储它们的模式的格式、是否使用压缩等密切相关。
  • 第二种方法是使用 HCatalog 的功能将 Hive 数据加载到 Pig 中。与前一点相比,这个过程有很多优点。HCatalog 提供了一种抽象的方式来查看文件的存储。它包装了来自 HDFS 的 metastore 和存储信息,为访问表提供了统一的视角。使用 HCatalog,您不再需要担心文件的存储位置、模式的格式或是否使用压缩。您只需要指定 HCatalog 加载器的表名,它就可以在幕后完成必要的管道工作,并绘制底层的存储格式、位置和模式。现在用户不知道表的位置、分区、模式、压缩类型和存储格式。HCatalog 通过表级抽象简化了这一点,并在幕后做了大量工作。

出口变现

导出设计模式是使用 HCatalog 函数实现的,该函数将 Pig 关系中的数据存储到 Hive 表中。HCatalog 提供了一个 HCatStorer 接口,将 Pig 关系的内容存储到 HCatalog 管理的 Hive 表中。有关为什么 HCatalog 接口是加载和存储操作的最佳选择的更多信息,请参考上一节入口实现中的第二点。

下图说明了这些设计模式遵循的方法:

The egress implementation

Hive 和 PIG 的结合

代码片段

下面的代码示例使用了一个零售交易数据集样本。包含 T0、T1、T2、T3、T4、T5、T6、T7、T8 等属性。这个数据已经存储在 Hive 中来说明这个例子。Hive 的本地存储 RCFile,包含此表的内容,用于解释直接访问;HCatalogLoader在下例中也有说明。

进入码

下面的代码说明了从 Hive 获取数据。

使用 RCFile 导入数据

下面的代码说明了HiveColumnarLoader从存储在 RCFile 中的 Hive 表加载数据的用法:

/*
Register the Piggybank jar file to be able to use the UDFs in it
*/
REGISTER '/usr/share/pig/contrib/piggybank/java/piggybank.jar';

-- Register Hive common and exec jars
REGISTER '/usr/lib/hive/lib/hive-common-0.11.0.1.3.0.0-107.jar';
REGISTER '/usr/lib/hive/lib/hive-exec-0.11.0.1.3.0.0-107.jar';

/*
Load retail_transactions_rc  RCfile and specify the names of the columns of the table and their types in the constructor of HiveColumnarLoader.
*/
transactions = LOAD '/apps/hive/warehouse/transactions_db.db/retail_transactions_rc' USING org.apache.pig.piggybank.storage.HiveColumnarLoader('transaction_no int,transaction_date string,cust_no int,amount double,category string,product string,city string,state string,spendby string');

/*
* Some processing logic goes here which is deliberately left out to improve readability
*/

/*
Display the contents of the relation transactions on the console
*/
DUMP transactions;
使用 HCatalog 导入数据

下面的代码展示了如何使用 HCatalog 从 Hive 加载数据:

/*
Specify the table name as the input to the HCatLoader function provided by HCatalog.
This function abstracts the storage location, files type, schema from the user and takes only the table name as input
*/
transactions = LOAD 'transactions_db.retail_transactions' USING org.apache.hcatalog.pig.HCatLoader();

/*
* Some processing logic goes here which is deliberately left out to improve readability
*/

/*
Display the contents of the relation transactions on the console
*/
DUMP transactions;

导出代码

下面的代码展示了如何使用 HCATTOR 将数据导出到 Hive:

-- Register piggybank and hcatalog-pig-adapter jars
REGISTER '/usr/share/pig/contrib/piggybank/java/piggybank.jar';
REGISTER '/usr/lib/hcatalog/share/hcatalog/hcatalog-pig-adapter.jar';

/*
Load the transactions dataset into the relation transactions
*/
transactions = LOAD '/user/cloudera/pdp/datasets/hive/retail_transactions.csv' USING org.apache.pig.piggybank.storage.CSVLoader() AS (transaction_no:int, transaction_date:chararray, cust_no:int, amount:double, category:chararray, product:chararray, city:chararray, state:chararray, spendby:chararray);

/*
* Some processing logic goes here which is deliberately left out to improve readability
*/

/*
Specify the Hive table name transactions_db.retail_transactions as the input to the HCatStorer function.
The contents of the relation transactions are stored into the Hive table.
*/
STORE transactions INTO 'transactions_db.retail_transactions' using org.apache.hcatalog.pig.HCatStorer();

结果

应用进气设计模式后,Hive 表中的数据以 Pig 关系加载,并准备进一步处理。使用HCatLoader时,正确解释 HCatalog 的数据类型如何映射到 Pig 类型很重要。除了 HCatalog 中映射到二进制的bytearray类型外,所有基本类型的 PIG 都映射到它们对应的 HCatalog 类型。在复杂数据类型中,HCatalog 的映射映射到 Pig 中的映射,HCatalog 的列表映射到 Pig 中的包,HCatalog 的struct映射到 Pig 中的元组。

应用导出设计模式,Pig 关系中的数据存储在 Hive 表中,以便在 Hive 中进行报告和具体分析。前段提到的HCatLoader的所有模式转换规则也适用于HCatStorerHCatStorer类接受代表分区表键值对的字符串参数。如果要在分区表中存储 Pig 关系的内容,应该强制指定这个参数。

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • chapter2/code/
  • chapter2/datasets/

半结构化数据的导入导出模式

本节描述半结构化数据的设计模式,如 XML、JSON 和大型机数据。我们选择了 XML 和 JSON,因为它们是互联网数据交换最流行的编码格式。大量数据被锁定在文档、期刊和内容管理系统中,这可能会从分析中受益。之所以选择大型机数据作为这个用例,主要是因为它在很多企业中是一个相对未被探索的领域,随着新模型的出现,它最终可能会被普及。

主机摄入模式

大型机摄取模式描述了如何使用 Pig Latin 将从大型机导出的数据摄取到 Hadoop 文件系统中,以便在数据管道上进一步处理。

我们将讨论处理存储在大型机中的数据与企业之间的相关性,并对大型机内部存储和访问数据的各种方式有更深入的了解。我们还将结合 Pig 讨论摄取的动机和大型机数据的用例。您还将学习 Pig 如何比使用用 Java 编写的 MapReduce 代码(使用 UDFs)更直观地获取数据。

下面关于这个模式的实现级细节的讨论旨在让您熟悉重要的概念和适用的替代方案。一个示例代码片段用于从 Pig 语言的角度更好地理解模式,然后是使用模式的结果。

背景

大型机似乎还有很长的路要走,很难想象一个没有这些老黄牛来处理这些事务几十年的世界。这就是这些机器的稳定性。即使在极高的数据吞吐量下,它们也能忠实地运行,一秒钟也不闪烁。难怪这些工程奇迹已经成为从飞机和汽车到金融服务和政府的商业支柱,多年来不断销售、跟踪、插入和更新这些实体的每一笔交易。

凭借 20 世纪 60 年代推动工业革命的经验,大型机随着时间的推移而发展,变得更加强大,并且能够处理它们设计的特定高吞吐量事务性工作负载。如今,他们使用定制的处理器和其他高端硬件来实施虚拟化、纵向扩展并展示事务完整性,尽管吞吐量极高。显然,大型机可以提供比任何其他体系结构更好的结果,具有极高的吞吐量、难以置信的高可用性、可靠性和顶级安全性。

动机

Hadoop 在从大型机卸载大量事务数据并对其进行批处理方面发挥着越来越重要的作用。这与通过将处理从昂贵的定制系统转移到包含 Hadoop 框架的商业硬件来提高大型机的事务吞吐量和批处理时间是一致的。同样,当大型机的批处理能力无法有效扩展时(在一个价位和性能范围内),将处理工作卸载给 Hadoop 是有好处的,因为 Hadoop 可以以更好的性价比完成这项工作。如下图所示:

Motivation

批处理和卸载到 Hadoop

用例

这个设计模式可以应用于解决以下用例:

  • 将数据从大型机迁移到 Pig,以与其他系统的数据集成并创建高级分析。
  • 将非关键批次工作负载卸载到 Pig,大幅释放大型机吞吐量。
  • 在 Pig 中重写 COBOL 代码带来了可重用性、可维护性、简单性和紧凑性的优点。

模式实现

通过卸载,Hadoop 的相关处理意味着将 COBOL 编写的代码重写到 MapReduce,并从大型机传输数据。

COBOL 是通用语言,用于大型机访问 DB2 和其他数据库,执行批处理和处理在线事务。不适合在互联网上实现复杂的算法,可能有利于更新业务需求,如风险建模、预测分析等。

为了将 COBOL 代码迁移到 MapReduce,我们可以选择一些在大型机中实现的函数,这些函数可以遵循 mapper 和 Reduce 的结构。例如,遗留的 COBOL 代码可以对数十亿条记录进行排序,将它们与其他数据源进行合并和分组,并执行复杂的转换,这比 Pig 中的 COBOL 更有效。在 Pig 代码中加入 Java UDF 函数,可以对数据管道进行高级分析;这种结合可能会创造奇迹。因此,将代码迁移到 Pig Latin 以有效地执行特定的处理可以带来丰厚的回报。

迁移大型机数据有其自身的一系列挑战。通常,大型机在内部将各种类型的数据存储在 VSAM 文件、平面文件和数据库管理系统中。对于 Hadoop 来说,要访问这些数据,需要将其转换成它能理解的格式,然后通过文件传输机制物理传输到 Hadoop 集群。使用特定的实用程序(如 IDCAMS),您可以将 VSAM 文件转换为平面文件供 Hadoop 使用。

每个大型数据库管理系统都有自己的专用工具,可以了解数据库管理系统的内部文件存储格式,并将其转换为平面文件。我们可能需要处理这些平面文件从大型机中的一个代码页到 Hadoop 集群的目标机器中的另一个代码页的转换。一般来说,从主机导出的平面文件是反规格化的 CSV 格式。如下图所示:

Pattern implementation

大型机数据提取和摄取到 Hadoop 中

为了理解 CSV 格式每一列的物理布局和定义,使用了一个专用于大型机的字帖。在 Hadoop 中,字帖提供的信息被用作分析 CSV 和解码 CSV 文件含义的模式。因此,主机数据的摄取需要两个输入:一个是平面文件本身,另一个是字帖。

Pig 有内置的加载器,可以读取 CSV 文件,但是解析必须在 CSV 上用字帖的内容完成。因此,必须编写一个 Java UDF 或自定义加载器来实现这一点。

代码片段

下面的代码示例使用了一个数据集,该数据集包含从大型机到 CSV 文件的与车辆维修索赔相关的示例车辆保险索赔数据。VSAM 文件中数据元素的元数据和物理布局在字帖中定义。字帖包含claimpolicyvehiclecustomer,garage details等字段。下一节中的 Java 代码片段解析字帖,检索元数据,并使用它将数据加载到 CSV 文件中。

以下 Pig 脚本使用自定义加载器将从大型机提取的数据加载到 CSV 文件中。这里VSAMLoader使用字帖文件确定 CSV 文件的元数据并加载:

/*
Register custom UDF vsamloader.jar and  cb2java jar which is a dynamic COBOL copybook parser for Java
*/
REGISTER '/home/cloudera/pdp/jars/vsamloader.jar';
REGISTER '/home/cloudera/pdp/jars/cb2java0.3.1.jar';

/*
Load the contents of the automobile insurance claims dataset using custom UDF.
VSAMLoader uses the copybook file to parse the data and returns the schema to be used to load the data
*/
data = LOAD '/user/cloudera/pdp/datasets/vsam/automobile_insurance_claims_vsam.csv' USING com.mycustomloader.vsamloader.VSAMLoader();

/*
* Some processing logic goes here which is deliberately left out to improve readability
*/

-- Display the contents of the relation data on the console
DUMP data;

-- Display the schema of the relation data
DESCRIBE data;

以下是 VSAMLoader 的 Java 代码片段,这是一个自定义的加载器实现:

@Override
public ResourceSchema getSchema(String arg0, Job arg1) throws IOException {
  .
  .
  while (it.hasNext()) {
    Map.Entry pairs = (Map.Entry) it.next();
    //Get the next key/value pairs
    String key = (String) pairs.getKey();
    String value = (String) pairs.getValue();
    /*For Group and Alphanumeric types in copybook, return
    pig compliant type chararray*/
    if (value.toString()
    .equals("class net.sf.cb2java.copybook.Group")
    || value.toString().equals("class net.sf.cb2java.copybook.AlphaNumeric")){
       fieldSchemaList.add(new FieldSchema(key,
        org.apache.pig.data.DataType.CHARARRAY));
      }
    /*For Decimal type in copybook, return
    pig compliant type integer*/
    else if (value.toString()
    .equals("class net.sf.cb2java.copybook.Decimal")){
      fieldSchemaList.add(new FieldSchema(key,
        org.apache.pig.data.DataType.INTEGER));
    }
    // Else return default bytearray
    else
    {
       fieldSchemaList.add(new FieldSchema(key,
       org.apache.pig.data.DataType.BYTEARRAY));
    }
    }
  return new ResourceSchema(new Schema(fieldSchemaList));
}

vsamloader JAR 实现的自定义加载器代码中,我们使用外部 API 解析字帖文件,得到所有的值。然后,我们从 Pig API 及其getSchema()方法中实现一个名为LoadMetaData的接口,它将返回我们通过解析字帖获得的模式。使用类型为FieldSchemaArrayList类,它将最终在字帖文件中填写列名及其数据类型。这个ArrayList作为新模式返回,小 PIG 加载 VSAM 文件时会用到。

结果

将该模式应用于主机数据提取的结果是将平面文件中的数据加载到 Pig 拉丁关系中进行进一步处理。因为 Pig 中没有现成的函数来理解字帖格式,所以我们通过自定义加载器来扩展 Pig。必须注意在自定义加载器中正确映射模式,因为并非所有的 COBOL 数据类型都可以轻松映射到 Java 对应类型。例如,COBOL 对布尔值和日期类型的支持是有限的,所以我们必须实现一个特殊的转换来用 Java 处理它以获得准确的结果。有关更多信息,请参见下一节中的链接。

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • chapter2/code/
  • chapter2/datasets/

XML 接收输出模式

本节介绍如何使用 Pig Latin 将 XML 编码的文档或日志的内容导入和导出到 Hadoop 文件系统,以便在数据管道上进一步处理。

我们将讨论如何处理存储在 XML 中的数据与企业的相关性,了解 Pig 访问 XML 数据(原始 XML 和二进制)的各种方式。您将了解使用原始和二进制 XML 解析的优缺点,然后了解将 XML 数据与 Pig 相结合的动机和用例。您还将学习 Pig 如何比使用用 Java 编写的 MapReduce 代码更直观、更高效地获取数据。

下面关于这个模式的实现级细节的讨论旨在让您熟悉重要的概念和适用的替代方案。一个示例代码片段用于从 Pig 语言的角度更好地理解模式,然后是使用模式的结果。

背景

XML 是以直观的方式存储和传输数据的最广泛使用的协议之一,这使得人类和机器相对容易理解数据的含义。XML 是文本格式,不是二进制格式。它具有用相关元数据编码数据的特殊能力,并且可以自己阐明其含义。由于这一特性,XML 已经成为大多数互联网应用事实上的数据传输标准。XML 的通用性在于它不仅可以表示文档,还可以表示网络服务中任意的数据结构。今天,我们看到数以千计的基于 XML 的分类法、信息交换格式和文档格式——如微软 Office、SOAP、RSS、XHTML 和 ATOM——正在被广泛使用。从分析的角度来看,所有这些基于 XML 的数据存储和传输格式都包含了丰富的信息。

动机

使用 Hadoop 接收和输出 XML 本来就很复杂,在灵活性上也有一些妥协。复杂性来自于任意的嵌套,元数据本身所需要的空间可能是惊人的。尽管 XML 通过包含标签和其他可选字段为您提供了模拟现实世界的灵活性,并使用大量元数据信息对数据进行编码,但它显然会导致属性的深度嵌套,并使大量数据的计算更加复杂和耗时。这意味着将 XML 文档加载到计算机内存中是一项非常复杂的 CPU 密集型工作。

由于上述复杂性,Hadoop 提供了许多优势来更快地处理大型复杂的 XML 数据,并且通过接收、转换和导出 XML 供下游系统进一步使用,它可以使用更低成本的操作。要在 Hadoop 中处理 XML,您可能必须考虑处理 XML 数据的性质和上下文。

摄取原始 XML 的动机

Hadoop 中摄取和处理 XML 的一个原因是当你事先不知道 XML 模式,在读取文件时想要理解它。该方法的要点如下:

  • XML 数据以其原始格式加载,在查询过程中找到其模式,并在发现后执行其转换。
  • 这种方法本质上更具探索性;它提供了快速的初始加载,因为数据没有使用序列化以二进制格式进行清理或存储。
  • 它支持更大的灵活性,因此可以使用多个模式来解析不同类型分析查询的 XML。
  • 它适用于定义良好的格式,这可能会导致为每个查询解析 XML 数据,并对查询性能产生轻微影响。

摄取二进制 XML 的动机

在 Hadoop 中摄取和处理 XML 的另一个原因是当您已经知道了 XML 的模式,并且想要对 XML 执行高性能查询时。该方法的要点如下:

  • XML 必须首先被解析,以二进制格式序列化到磁盘,跨节点拆分,压缩,并针对查询进行优化。
  • 如果在加载过程中需要大量的清理和重新格式化,这种方法是可行的。
  • 如果需要对生产工作负载执行重复查询,这是合适的。
  • 如果加载时模式未知,则此方法不适合,因为以可查询格式加载、预处理和存储 XML 需要很长时间。

XML 输出的动机

Hadoop 可用于从 HDFS 的 CSV 和 Hive 表等结构化数据创建和输出 XML 文件。XML 文件也可以直接摄取到 Hadoop 中,这样就可以由 Pig 进行验证或转换,写回 XML,满足下游系统的交换格式。

用例

XML 摄取模式可用于以下用例,以解决以下问题:

  • 它可用于从内容管理系统(如技术文档、参考手册和期刊)接收基于 XML 的文档数据。摄取是在使用 Lucene 创建搜索索引并对其执行分析之前完成的。
  • 它可以用来接收包含 SOAP 和 EDXL-CAP 类型的消息文本的 XML 日志,并分析系统之间的请求和响应。例如,可以从网络故障管理系统中提取 XML 编码的消息,并对其进行分析,以了解或预测子系统未来的故障。

当 HDFS 的结构化数据(分离的平面文件或配置单元表)需要转换为可扩展标记语言进行处理和序列化时,可以使用可扩展标记语言导出模式,以便上游系统可以使用可扩展标记语言进一步处理数据。

模式实现

Pig 提供结构直接加载原 XML 文件,支持加载预处理后的 XML 文件。

XML 原始摄取的实现

pigybank 库提供XMLLoader功能访问 XML 文件的内容。XMLLoader该函数的参数是一个内部转换成单记录元组的 XML 标记名。该记录包含开始 XML 标记和结束 XML 标记中包含的文本。使用从 XML 文件返回的元组,您可能必须执行进一步的解析,以将记录级 XML 值分解为它们的组件值;一般使用正则表达式函数REGEX_EXTRACT进行展平投影。

XML 二进制摄取的实现

将 XML 转换为二进制格式进行拆分是一个两步的过程。

  • 第一步,为了解析 XML 文档,可以将文件完全读入基于内存的数据结构,使用 DOM 等解析器可以随机访问数据的所有元素。或者,您可以连续访问文件的内容,并一次控制一个解析步骤。这可以通过 XML SAX 解析器来完成,并且执行速度稍慢。DOM 解析的优点是可以链接多个处理器,但是编程比较困难,而 SAX 解析的优点是容易编程和拆分。但是,另一方面,SAX 执行起来很慢,因为它是一种用于解析 XML 文档的串行访问机制。
  • 第二步,将解析后的 XML 转换成 Hadoop 可以处理的可拆分二进制格式,Avro 是执行符合这些标准的序列化的最佳选择,这有助于将 XML 文档转换成字节流,并以磁盘格式存储。Avro 是专门为 Hadoop 设计的,使其成为一种高度可压缩和可分离的二进制格式,与序列文件非常相似。与序列文件不同,只能通过 Java API 访问,Avro 文件可以从 C、C++、C#、Ruby、Python 等其他语言访问。凭借其独特的互操作性格式,Avro 文件可以从一种语言编写的代码传输到另一种语言编写的不同代码,甚至可以从 C 语言等编译语言传输到 Pig 等脚本语言。
  • 每个 Avro 文件都用元数据包装了 XML 文件的底层内容,元数据包含反序列化或读取内容所需的信息。Avro 将元数据与文件的实际内容一起存储在文件中,这使得其他程序更容易首先理解元数据,然后处理嵌入的数据。一般元数据以 JSON 格式存储,数据以二进制格式存储。
  • Avro 文件还包括一个标签,用于在集群的多个节点上划分数据。在访问序列化的 Avro 文件之前,您必须将 XML 文件准备成 Avro 格式,并使用 piggybank 的AvroStorage将其读入 Pig 拉丁语的关系。

下图描述了上述实现方面:

The implementation of the XML binary ingestion

XML 数据的进入和退出

代码片段

下面的代码示例使用了一个包含 MedlinePlus 健康讨论的 XML 数据集。

【T0】XML 原始摄取代码

XML 数据由数据元素的标签组成,如主题标题、相关网站、主要语言、日期、词汇、摘要、成员资格等其他语言的相关健康主题和内容。下面的代码片段解析 XML 标记,并将内容作为关系加载到 Pig 拉丁脚本中:

-- Register piggybank jar
REGISTER '/home/cloudera/pig-0.11.0/contrib/piggybank/java/piggybank.jar';

/*
XMLLoader accesses the specified XML file and retrieves the record level value to be stored in the tuple data specified by the parameter to the XMLLoader.
*/
data = LOAD '/user/cloudera/pdp/datasets/xml/mplus_topics_2013-09-26.xml' USING org.apache.pig.piggybank.storage.XMLLoader('article');

/*
* Some processing logic goes here which is deliberately left out to improve readability
*/

/*
Print the contents of the relation data to the console
*/
DUMP data;

【T0】XML 二进制摄取代码

以下代码执行 XML 的二进制摄取:

-- Register piggybank jar
REGISTER '/usr/share/pig/contrib/piggybank/java/piggybank.jar';

-- Register Avro and JSON jar files
REGISTER '/home/cloudera/pdp/jars/avro-1.7.4.jar';
REGISTER '/home/cloudera/pdp/jars/json-simple-1.1.1.jar';

/*
Assign the alias AvroStorage to piggybank's AvroStorage UDF
*/
DEFINE AvroStorage org.apache.pig.piggybank.storage.avro.AvroStorage();

/*
Load the dataset using the alias AvroStorage into the relation health_topics
*/
health_topics = LOAD '/user/cloudera/pdp/datasets/xml/mplus-topics_2013-09-26.avro' USING AvroStorage;

/*
* Some processing logic goes here which is deliberately left out to improve readability
*/

-- Print the contents of the relation health_topics to the console
DUMP health_topics;

下图描述了将 XML 文件转换为 AVRO 所涉及的步骤:

The XML binary ingestion code

XML 到 Avro 预处理

我们使用第三方工具从给定的 XML 文件生成 XSD,并使用 schemagen 生成 JAXB、Avro 绑定和 Avro 模式。在内部,schemagen 使用 JAXB 绑定编译器 XJC;;然后,它从 XSD 模式文件生成一个代码模型。然后执行 XJC 插件以 JSON 格式创建 Avro 模式。XJC 插件调用 Avro 的 Java 模式编译器来生成新的 Java 类,以便序列化到 Avro 和从 Avro 序列化。

【T0】XML 导出代码

以下是将 CSV 文件内容转换为 XML 格式的 Pig 脚本。

PIG

自定义存储功能 XMLStorage 用于完成 CSV 文件内容到 XML 格式的转换:

/*
Register custom UDF jar that has a custom storage function XMLStorage to store the data into XML file.
*/
REGISTER '/home/cloudera/pdp/jars/xmlgenerator.jar';

/*
Load the transactions dataset using PigStorage into the relation transactions
*/
transactions = LOAD '/user/cloudera/pdp/datasets/hbase/transactions.csv' USING PigStorage( ',' ) AS (
    listing_id: chararray,
    transaction_date: chararray,
    customer_id: int,
    age: chararray,
    residence_area: chararray,
    product_subclass: int,
    product_id: long,
    amount: int,
    asset: int,
    sales_price: int);

/*
* Some processing logic goes here which is deliberately left out to improve readability
*/

/*
Custom UDF XMLStorage generates the XML file and stores it in the xml folder
*/
STORE transactions INTO '/user/cloudera/pdp/output/xml' USING com.xmlgenerator.XMLStorage();

【T0】XML 存储

以下是 XML 存储的代码:

protected void write(Tuple tuple)
  {
    // Retrieving all fieds from the schema
    ResourceFieldSchema[] fields = schema.getFields();

    //Retrieve values from tuple
    List<Object> values = tuple.getAll();

    /*creating xml element by using fields as element tag
    and tuple value as element value*/
    Element transactionElement =  
    xmlDoc.createElement(XMLStorage.elementName);
    for(int counter=0;counter<fields.length;counter++)
    {
      //Retrieving element value from value
      String columnValue = 
      String.valueOf(values.get(counter));
      //Creating element tag from fields
      Element columnName = 
      xmlDoc.createElement(fields[counter].getName().toString().trim());
      //Appending value to element tag
      columnName.appendChild
      (xmlDoc.createTextNode(columnValue));
      //Appending element to transaction element
      transactionElement.appendChild(columnName);
    }
    //Appending transaction element to root element
    rootElement.appendChild(transactionElement);
  }

write该方法以元组为输入,表示 CSV 文件中的一行。此方法为元组中的每个字段创建一个 XML 元素。对 CSV 中的所有行重复此过程,以生成一个 XML 文件。

结果

将此模式应用于 medline XML 文件的结果是将数据加载到 Pig Latin 关系中进行进一步处理。请确保 XML 文件格式正确,所有元素都有开始和结束标记,否则XMLLoader可能会返回无效值。

应用导出设计模式,关系事务中的数据被写入指定路径的 XML 文件中。

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • chapter2/code/
  • chapter2/datasets/

JSON 进入退出模式

JSON 摄取模式描述了如何从 Hadoop 文件系统中通过 Pig Latin 摄取并输出表示为 JSON 的数据,从而进一步处理数据管道中的数据。

我们将讨论如何处理 JSON 中存储的数据与企业的相关性,并了解可以使用 Pig 访问和存储 JSON 数据的各种方式(简单 JSON 和嵌套 JSON)。您将了解使用简单 JSON 和嵌套 JSON 解析的优缺点,了解将 JSON 数据与 Pig 相结合的动机和用例。您还将学习 Pig 如何比用 Java 编写的 MapReduce 代码更直观地摄取这些数据(通过使用象鸟等外部库)。

下面关于这个模式的实现级细节的讨论旨在让您熟悉重要的概念和替代方案(如果适用的话)。一个示例代码片段用于从 Pig 语言的角度更好地理解模式,然后是使用模式的结果。

背景

JSON 是构造文本的另一种方式。JSON 是一种数据交换格式,它以分层的方式描述数据,这样机器和人类都可以读取数据并对其进行操作。

JSON 以一种简单得多的方式表示数据,更像是一个键值对,其中的值可以是非常原始的,比如整数、字符串和数组。JSON 不支持像 XML 这样极其复杂和嵌套的数据类型。它不太冗长,只需要一个查找函数来检索值,因为数据存储在键值对中。这使得 JSON 非常紧凑,适合更有效地表示数据,不像 XML。在 XML 中,数据以复杂的嵌套方式由丰富的数据类型表示,这使得解析 XML 树变得非常复杂。在现实世界中,JSON 用于存储简单的数据类型,而 XML 用于建模数据类型的复杂性,这提供了一些功能,使您能够更好地表达数据的结构。

动机

JSON 作为最受欢迎的数据表示标准之一的崛起,很大程度上是由于社交网络公司的强劲崛起,如领英、推特和脸书。这些企业和许多其他需要与外部世界交换内部业务数据(如社交对话或任何占用空间较小的数据)的公司主要转向能够在不增加 XML 复杂性的情况下承载简单高效负载的 API。JSON 是这些 API 的首选格式,因为它的简单性和作为关键数据源的实现使得解析变得容易。

随着社交媒体的兴起,我们可以看到 NoSQL 数据库的出现,这使得 JSON 成为他们的支柱。许多这样的数据库,如 MongoDB、CouchDB 和 Riak,都使用 JSON 作为它们的主要存储格式。由于 JSON 的使用,这些数据库表现出极高的性能特点和横向扩展的能力。这些数据库是专门为互联网规模的应用而设计的,其中实时响应的需求是最重要的。

以非社交媒体为中心的企业也在加速传播。目前,JSON 用于存储具有多个标题和其他键值对的日志文件。JSON 格式的日志数据很好地表示了用户会话和用户活动,每个用户活动的信息都嵌套在会话信息下。这种 JSON 格式的数据嵌套在执行高级分析时提供了天然的优势。对于处理传感器数据的企业来说,JSON 也是一个很好的选择,传感器数据包含为不同测量收集的各种属性。

虽然 JSON 作为快速检索和更高效承载互联网有效载荷的首选存储格式表现良好,但在很多用例(如日志处理、传感器分析)中,JSON 中表示的数据不仅用于搜索,还广泛集成其他企业数据资产进行分析。这种集成意味着对 JSON 和其他结构化数据的组合进行批处理。下面几节讨论的接收设计模式描述了将 JSON 接收到数据管道中的方法。

批处理数据管道的输出有时可以概括为 JSON 表示的现成数据。这适用于使用 JSON 将批处理 JSON 输出馈送到 NoSQL 数据库的用例,以及 JSON 可以用作 web 服务的负载的用例。导出设计模式展示了我们如何使用 Pig 将数据管道中存储的数据转换为 JSON 格式。

用例

以下是 Pig 摄取和输出 JSON 数据的用例:

  • 使用摄取设计模式将 JSON 数据集成到 Pig 关系中,以便数据管道中的组合数据可以用于分析。
  • 使用摄取设计模式来消费来自 Twitter 和其他社交媒体来源的 JSON 应用编程接口,以执行高级分析,例如情感挖掘。
  • 存储在 JSON 中的传感器数据是使用机器故障分析的捕获设计模式捕获的。
  • 使用导出设计模式以 JSON 格式存储 HDFS 现有平面文件的内容。这种模式对于以 JSON 格式存储复杂数据集成或转换管道的结果以供下游系统访问也很有用。

模式实现

下面部分展示了出入口的实现。

进入实施

JSON 可以通过JSONLoader函数加载到 Pig 关系中,将 JSON 文件的内容加载到地图中。JSONLoader该功能可以使用或不使用模式信息。

  • 如果在JSONLoader中提供了模式信息,那么 Pig 和 JSON 数据类型之间的映射是直接的,并且遵循指定的模式。
  • JSONLoader中没有提供模式信息时,Pig 关系的数据类型设置为默认bytearray,在执行周期的后期推断实际模式。要处理一个大的 JSON 文件并对其执行并行处理,您可能必须用每行一个 JSON 对象格式来格式化 JSON 文件。当您需要解析超过 HDFS 存储块大小的非常大的 JSON 文件时,以及当您可以控制 JSON 的格式以每行包含一个 JSON 对象时,这个先决条件是适用的。
  • 当 JSON 文件不能格式化为每行包含一个 JSON 对象时,MapReduce 无法拆分 JSON 文件,因为 JSON 是嵌套的,在不同的级别使用相同的元素。JSON 格式与 XML 形成对比,后者有一个开始和结束标记来表示嵌套数据结构的边界。这个问题的解决方案在象鸟库LZOJSONLoader的实现中得到了解决,允许确定嵌套 JSON 文件的划分边界。大象库是一个开源的实用程序库,用于处理 JSON 和 Twitter 提供的其他格式。在https://github.com/kevinweil/elephant-bird有售。

出口变现

使用 JsonStorage功能,以 JSON 格式存储 PIG 关系的内容。Pig 关系的内容在输出中存储为单个 JSON 行。执行模式映射时,JsonStorage函数将 Pig 元组映射到 JSON 对象。同样,它将 Pig 映射到一个 JSON 对象,Pig 包对应于 JSON 数组。

下图描述了如何使用 Pig 摄取和排出 JSON 的总体思路:

The egress implementation

JSON Hadoop 集成

代码片段

下面的代码示例使用了来自安然语料库的样本数据集,该数据集包含来自 150 个用户的电子邮件,平均每个用户有 757 条消息。数据集中的字段是 T0、T1、T2、T3、T4、T5、T6 和 T7。

进入码

下面的部分展示了将 JSON 格式存储的数据摄入 Pig 关系的代码及其解释。

简单 JSON 的代码

使用JsonLoader加载 JSON 文件的代码如下:

/*
Use JSONLoader UDF, it takes in the parameter of the JSON schema and loads the contents of the JSON file emails.json into a map enron_emails
*/
enron_emails = LOAD '/user/cloudera/pdp/datasets/json/emails.json' USING JsonLoader('body:chararray, from:chararray, tos:chararray, ccs:chararray, bccs:chararray, date:chararray, message_id:chararray, subject:chararray');

/*
* Some processing logic goes here which is deliberately left out to improve readability
*/

/*
Display the contents of the relation enron_emails on the console
*/
DUMP enron_emails;

重要的是注意到JsonLoader没有使用AS子句来提供模式。

嵌套 JSON 的代码

加载嵌套 JSON 的 PIG 脚本如下图,我们用象鸟库来实现:

/*
Register elephant-bird and JSON jar files
*/
REGISTER '/home/cloudera/pdp/jars/elephant-bird-core-3.0.5.jar';
REGISTER '/home/cloudera/pdp/jars/elephant-bird-pig-3.0.5.jar';
REGISTER '/home/cloudera/pdp/jars/json-simple-1.1.1.jar';

/*
Use ElephantBird's JsonLoader for loading a nested JSON file
The parameter –nestedload denotes nested loading operation
*/
emails = LOAD '/user/cloudera/pdp/datasets/json/emails.json' USING com.twitter.elephantbird.pig.load.JsonLoader('-nestedLoad');

/*
* Some processing logic goes here which is deliberately left out to improve readability
*/

/*
Display the contents of the relation emails on the console
*/
DUMP emails;

导出代码

以下部分展示了与 JSON 格式相关的 Pig 中存储的导出数据的代码及其说明:

/*
Load the JSON file using JsonLoader to the relation enron_emails
*/
enron_emails = LOAD '/user/cloudera/pdp/datasets/json/emails.json' USING JsonLoader('body:chararray, from:chararray, tos:chararray, ccs:chararray, bccs:chararray, date:chararray, message_id:chararray, subject:chararray');

/*
* Some processing logic goes here which is deliberately left out to improve readability
*/

/*
Use JsonStorage to store the contents of the relation to a json file
*/
STORE enron_emails into '/user/cloudera/pdp/output/json/output.json' USING JsonStorage();

结果

应用设计模式会导致 JSON 数据以 Pig 关系存储。如果字段解析不正确或找不到字段,JsonLoader将在 Pig 关系中存储空值。JsonLoader不关心构造函数中字段的顺序;您可以按任何顺序指定它们。JsonLoader只要字段名匹配,就可以正确解析。如果存在类型不匹配,则根据可行性进行JsonLoader自动类型转换。可以把int铸成string,但不能把string铸成int。作为最佳实践,您可以考虑使用没有模式定义的JsonLoader函数来理解 JSON 对象中所有键的顶层视图,并更好地理解数据。

应用导出设计模式将导致来自 Pig 关系的数据以 JSON 格式存储。JsonStorage功能使用缓冲技术以 JSON 格式存储。这种缓冲能力用于加载大容量数据,从而提高存储性能。您可以在JsonStorage构造函数中以千字节为单位指定固定大小的缓冲区。

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • chapter2/code/
  • chapter2/datasets/

总结

在本章中,我们从了解企业环境中的数据类型开始,并讨论每种数据类型的相关性、它们在企业中的使用以及 Hadoop 如何处理这些数据。

在下一节中,我们从更仔细地查看特定类型的数据开始,并将入口和出口设计模式应用于它们。我们涵盖了非结构化、结构化和半结构化类别中最相关的数据类型。我们还试图突出高级数据类型(如图像和大型机)的设计模式,以考虑 Pig 的适应性和可扩展性。在本书展示的每个设计模式中,我们从背景细节开始,了解模式的上下文相关性,然后了解模式对特定数据类型的动机和适用性。通过线程讨论了代码和模式的实现,简化了设计模式的实现。我们讨论了为什么 Pig 更好,并讨论了解决设计模式中特定情况的各种选项。

在下一章中,我们将了解更多可以应用于各种数据格式的数据分析模式。下一章的目标是让你通过分析数据,熟练运用 Pig 【T0】来理解数据的内容、脉络、结构和条件。Pig 提供了一组丰富的原语来分析数据,您将学习在分析企业级数据时使用的适当设计模式。您还将学习扩展 Pig 的功能,以适应数据分析的更高级用途。

三、数据分析模式

|   | 花时间看数据总是值得的。 |   |
|   | -证人,等等。 |

在前一章中,您研究了从 Hadoop 生态系统接收和输出不同类型数据的各种模式,以便开始分析过程的下一个逻辑步骤。在本章中,我们将了解与数据分析相关的最广泛使用的设计模式。本章将逐步诊断数据集是否有问题,最后将数据集转化为可用信息。

通过了解数据的内容、上下文、结构和条件,数据分析是深入了解 Hadoop 所吸收的数据的必要的第一步。

本章描述的数据分析设计模式在开始将数据清理为更有用的形式之前,收集 Hadoop 集群中关于数据属性的重要信息。在本章中,我们将查看以下部分:

  • 理解大数据背景下数据分析的概念和意义。
  • 数据分析中使用 Pig 的基本原理
  • 理解数据类型推理设计模式
  • 了解基本的统计分析设计模式。
  • 理解模式匹配设计模式
  • 理解字符串分析设计模式
  • 理解非结构化文本分析的设计模式

大数据的数据分析

不良数据隐藏在 Hadoop 吸收的所有数据中,但随着大数据数量和类型的惊人增加,不良数据的影响也在不断扩大。处理丢失的记录、格式错误的值和格式错误的文件会增加浪费的时间。令我们沮丧的是,我们看到了即使我们拥有也无法使用的数据量,我们手头拥有但随后丢失的数据,以及与昨天不同的数据。在大数据分析项目中,通常会收到一个非常大的数据集,但是关于它来自哪里、如何收集、字段的含义等信息并不多。在许多情况下,数据自收集以来经历了许多手和许多转换,没有人真正知道这一切意味着什么。

分析是对后续步骤中数据质量和数据处理适用性的度量。只是说明数据有问题。数据分析首先是对数据进行短期爆发式分析,以确定其适用性,了解挑战,并在数据密集型工作的早期阶段做出是否外出的决定。数据分析活动从定性的角度为您提供关于 Hadoop 吸收哪些数据的关键见解,并在获得任何分析见解之前评估将数据与其他来源集成所涉及的风险。有时,分析过程在分析过程的不同阶段进行,以消除不良数据并改进分析本身。

数据分析通过帮助我们从业务角度而不是分析角度理解数据,在提高整体数据质量、可读性和可加工性方面发挥了重要作用。在大数据信息管理平台(如 Hadoop)中构建数据分析框架,可以保证数据质量不会影响报告、分析、预测等决策所需的关键业务需求的结果。

传统上,数据汇总分析是根据其预期用途进行的,其中使用数据的目的是预先定义的。对于大数据项目来说,数据可能不得不以一种意想不到的方式被使用,必须进行相应的分析来解决如何重用数据的问题。这是因为大多数大数据项目处理对定义不明确的数据的探索性分析,这种分析试图找出如何使用数据或重新调整数据用途。要做到这一点,必须明确规定各种质量措施,如完整性一致性一致性正确性及时性合理性

在大数据项目中,采集元数据确定数据质量。元数据包括以下内容:

  • 数据质量属性
  • 商业规则
  • 起草
  • 清洁程序
  • 要素汇总和测量

大数据环境下数据质量的度量考虑以下因素:

  • 数据源
  • 数据类型
  • 数据的有意和无意使用
  • 将使用数据和结果来分析工件的用户组。

在上述各点中,数据类型在数据质量要求中起着至关重要的作用,如以下各点所述:

  • 结构化大数据分析:在处理大量结构化数据的大数据项目中,企业可以重用现有的处理关系数据库的数据质量流程,前提是这些流程可以扩展以满足大规模需求。
  • 分析非结构化大数据:社交媒体相关大数据项目聚焦质量问题,涉及从由俚语和缩写组成的非标准语言表达的句子中提取实体。社交媒体的分析价值可以通过与结构化交易数据关联来提取,因此社交网络上事件之间的关系可以映射到组织的内部数据,如供应链数据或客户人口统计数据。要执行此映射,必须分析非结构化文本以了解以下几点:
    • 如何提取对分析很重要的实体
    • 有多少数据拼错了?
    • 特定字段的通用缩写是什么?
    • 删除 stopword 的标准是什么?
    • 如何执行 stem?
    • 如何根据前面的单词理解单词的语境意义?

大数据分析维度

大数据分析跨多个维度进行,具体维度的选择通常取决于分析问题和时间/质量的平衡。有些维度重叠,有些维度根本不适用于这个问题。以下是衡量大数据质量的最重要方面:

  • Completeness: This dimension is a measure to know if you have all the data required to answer your queries. To evaluate if your dataset is complete, start by understanding the answers that you wish to seek from the data, and determine the fields needed and the percentage of complete records required to comfortably answer these questions. The following are a few of the ways completeness can be determined:

    • 如果我们知道主数据统计(记录、字段等的数量。)预先,完整性可以被确定为接收的记录与主数据记录的数量的比率。
    • 当主数据统计不可访问时,完整性通过空值的存在以下列方式来衡量:
      • 属性完整性:它处理特定属性中是否有空值。
      • 元组完整性:它处理元组中未知属性值的数量。
      • 值完整性:它处理半结构化 XML 数据中缺失的完整元素或属性。

    因为大数据分析的一个方面是问以前没有问过的问题,所以检查完整性维度就有了新的意义。在这种情况下,可以考虑执行一次迭代,向前看找到一系列你期望回答的问题,然后,向后推理找出回答这些问题需要什么样的数据。可以应用简单的记录计数机制来检查 Hadoop 集群中是否有总的期望记录。但是,对于跨越千兆字节的数据大小,此活动可能会很繁重,必须通过应用统计采样来执行。如果发现数据不完整,可以根据分析案例对丢失的记录进行修复、删除、标记或忽略。

  • Correctness: This dimension measures the accuracy of the data. To find out if the data is accurate, you have to know what comprises inaccurate data, and this purely depends on the business context. In cases where data should be unique, duplicate data is considered inaccurate. Calculating the number of duplicate elements in data that is spread across multiple systems is a nontrivial job. The following techniques can be used to find out the measure of potential inaccuracy of data:

    • 在包含离散值的数据集中,频率分布可以对数据的潜在不准确性给出有价值的见解。频率相对较低的值可能不正确。
    • 对于字符串,您可以创建字符串长度分布模式和低频标志模式作为潜在的疑点。同样,具有非典型长度的字符串可能会被标记为不正确。
    • 在连续属性的情况下,可以使用描述性统计数据(如最大值和最小值)将数据标记为不准确。

    对于大数据项目,建议确定精度需要哪些属性子集,知道应该有多少数据是准确的,并对数据进行采样以确定精度。

    需要注意的是,大海捞针的经典大数据问题中,有大量的分析值隐藏在不准确的数据中,可以认为是异常值。这些异常值不会被认为是不准确的,但是它们可以被标记并考虑用于用例的进一步分析,例如欺诈检测。

  • 相干性:这个维度衡量数据相对于自身是否有意义,判断记录之间是否有一致的关联,遵循数据集的内在逻辑。数据集一致性的度量可以通过以下方法理解:

    • 参照完整性:这个保证了表之间的关系是一致的。在大数据环境中,引用完整性不能应用于存储在 NoSQL 数据库(如 HBase)中的数据,因为没有数据的关系表示。
    • 值完整性:这个保证一个表中的值是否和自己一致。通过将这些值与预定义的一组可能值(来自主数据)进行比较,可以发现不一致的数据。

大数据采样分析注意事项

大数据采样是了解数据质量,通过只分析一部分人群,而不是深入到整个人群。选择样本最重要的标准之一是它的代表性,它决定了样本子集和总体之间的相似性。为了获得准确的结果,代表性应该更高。采样尺度对子集的代表性精度也有相当大的影响。

对大量数据进行采样以进行特征分析平衡了成本和质量之间的权衡,因为所有人进行特征分析的成本和复杂性都很高。在大多数情况下,分析活动并不是作为一种全面分析整个数据的机制来设计的,而是一个从正确性、一致性和完整性等维度获得数据整体质量的首过分析/发现阶段。随着数据在管道中移动,分析活动将迭代进行,这将有助于细化数据。因此,用于分析目的的数据采样在大数据中起着非常重要的作用。

虽然采样被认为是分析所必需的,但在将采样技术应用于大数据时建议谨慎。由于实现的复杂性和不适用性,并非所有的数据类型和收集机制都需要采样;当几乎实时地从传感器获取数据时,这是有效的。同样,并不是所有的用例都需要采样,这在获取数据进行搜索、推荐系统和点击流分析时是有效的。在这种情况下,必须完全不取样地查看数据。在这些情况下,取样会引入一些偏差,降低结果的准确性。

选择合适的采样技术对轮廓的整体精度有影响。这些技术包括非概率抽样和概率抽样方法。通常,我们不考虑非概率方法来执行数据分析活动。我们只限于概率抽样方法,因为这种方法提高了精度,减少了代表性偏差。为了更好的了解采样技术,数据简化模式 中数值简化-采样设计模式详见第六章

PIG 的采样支持

Pig 有本地支持使用SAMPLE操作符采样。我们使用了SAMPLE运算符来解释它在剖面分析的上下文中是如何工作的,并使用了基本的统计剖面分析设计模式。SAMPLE算子通过概率算法帮助你从人群中随机选择样本。内部算法非常初级,有时不能代表被采样的整个数据集。算法内部采用简单随机采样技术SAMPLE算子正在进化以适应更深奥的采样算法。更多关于前方道路的信息可以在https://issues.apache.org/jira/browse/PIG-1713找到。

在 Pig 中实现稳健采样方法的其他方法是利用 UDF 特征和 Pig 流对其进行扩展。

利用 Pig 的可扩展性,可以像 UDF 一样实现采样,但是使用起来非常复杂和费力,因为 UDF 最大的局限性就是只接受一个输入值,生成一个输出值。

也可以考虑使用 stream 实现采样,不受 UDFS 的限制。一个流可以接受任意数量的输入或发出任意数量的输出。r 语言有执行采样所需的函数,可以通过 Pig 流在 Pig 脚本中使用这些函数。这种方法的局限性在于,它通过将大部分数据保存在主存中来执行采样计算,而 R 必须安装在 Hadoop 集群的每个数据节点上,流才能工作。

LinkedIn 的 Pig 实用程序中的 Datafu 库已经发布了一些自己的采样实现。这个库现在是 Cloudera Hadoop 发行版的一部分。以下采样技术由 Datafu 实施:

  • 储层采样:它利用内存中的储层生成给定大小的随机样本。
  • Samplebykey :它根据某个键从元组中生成一个随机的样本。采用内部 分层随机抽样技术。
  • 加权样本:它通过赋权生成一个随机样本。

关于 Datafu 采样实施的更多信息,请访问 http://LinkedIn .github .io/数据单元/文档/当前/数据单元/清管器/取样/包装-摘要 html

数据分析中使用 Pig 的基本原理

在 Hadoop 环境中实现分析代码减少了对外部系统质量检查的依赖。下图描述了实施的高级概述:

Rationale for using Pig in data profiling

对 PIG 进行分析。

以下是在 Hadoop 环境中使用 Pig 进行数据分析的优势:

  • 在 Pig 中实现设计模式通过将分析代码直接移动到数据中来减少数据移动,从而提高性能并加速分析和开发过程。
  • 通过在 Pig 中实现这种模式,数据质量工作和数据转换在同一个环境中进行。这减轻了每次在 Hadoop 中接收数据时执行重复数据质量检查的手动冗余工作。
  • Pig 擅长于运行前摄入的数据模式未知的情况;它的语言特性为数据科学家提供了在运行时破译正确模式和构建原型模型的灵活性。
  • Pig 固有的发现数据模式和采样的能力使得在 Hadoop 环境中实现概要分析代码非常有利。
  • Pig 易于使用,这使得编写定制的分析代码变得更加容易。
  • Pig 通过链接复杂的分析工作流实现了分析过程的自动化,这对于定期更新的数据集非常有用。

既然我们已经理解了数据概要分析的概念和使用 Pig 进行概要分析的基本原理,我们将在下面的小节中探索一些具体的设计模式。

数据类型推理模式

本节描述了数据类型推断设计模式,其中我们使用 Pig 脚本来捕获关于数据类型的重要信息。

背景

Hadoop 中的大部分数据都有一些关联的元数据,这是对其特性的描述。元数据包括关于字段类型、长度、约束和唯一性的重要信息。我们也可以知道一个字段是否是强制的。元数据还用于通过检查刻度、测量单位、标签含义等来解释值。理解数据集的预期结构有助于解释其含义、描述、语义和数据质量。这种对数据类型的分析有助于我们了解它们在语法上是否一致(不同的数据集具有相同的一致格式规范)以及在语义上是否一致(不同的数据集具有相同的值集)。

动机

这种设计模式的意图是从 Hadoop 中摄取的数据中推断数据类型元数据。这个模型帮助你找到Type元数据与实际数据的对比,看看它们是否不一致,对分析有没有什么深远的影响。扫描数据类型和属性值,并将其与记录的元数据进行比较。基于该扫描,提出了适当的数据类型和数据长度。

这种设计模式用于检查数据集的结构,对于数据集,很少或没有现有的元数据,或者有理由怀疑现有元数据的完整性或质量。模式的结果有助于发现、记录和组织关于数据集元数据的“基本事实”。在这里,数据汇总分析的结果用于增量获取与数据元素的结构、语义和使用相关联的知识库。

用例

当你不得不摄取大量的结构化数据并且缺乏关于数据集的文档化知识时,你可以使用的设计模式。如果您需要使用未记录的数据进行进一步分析,或者需要对领域业务术语、相关数据元素、它们的定义、使用的参考数据集以及数据集中属性的结构有更深入的了解,则可以使用这种设计模式。

模式实现

这个模式被实现为一个独立的 Pig 脚本,里面有一个 Java UDF。实现这种模式的核心概念是发现列中的主要数据类型。首先,检查列值,找出它们是类型intlongdoublestring还是boolean。评估该值后,组合每种数据类型以找到频率。从这个分析中,我们可以找出哪个是占主导地位的(最频繁的)数据类型。

代码片段

为了说明的工作原理,我们考虑存储在 Hadoop 分布式文件系统 ( HDFS )中的零售交易数据集。包括Transaction IDTransaction dateCustomer IDPhone NumberProductProduct subclassProduct IDSales PriceCountry Code等属性。对于这个模式,我们感兴趣的是属性Customer ID的值。

PIG

下面是一个 Pig 脚本,演示了这种模式的实现:

/*
Register the datatypeinferer and custom storage jar files
*/
REGISTER '/home/cloudera/pdp/jars/datatypeinfererudf.jar';
REGISTER'/home/cloudera/pdp/jars/customdatatypeinfererstorage.jar';

/*
Load the transactions dataset into the relation transactions
*/
transactions = LOAD'/user/cloudera/pdp/datasets/data_profiling/transactions.csv'USING  PigStorage(',') AS (transaction_id:long,transaction_date:chararray, cust_id:chararray, age:chararray,area:chararray, prod_subclass:int, prod_id:long, amt:int,asset:int, sales_price:int, phone_no:chararray,country_code:chararray);

/*
Infer the data type of the field cust_id by invoking the DataTypeInfererUDF.
It returns a tuple with the inferred data type.
*/
data_types = FOREACH transactions GENERATEcom.profiler.DataTypeInfererUDF(cust_id) AS inferred_data_type;

/*
Compute the count of each data type, total count, percentage.
The data type with the highest count is considered as dominant data type
*/
grpd = GROUP data_types BY inferred_data_type;
inferred_type_count = FOREACH grpd GENERATE group ASinferred_type, COUNT(data_types) AS count;
grpd_inf_type_count_all = GROUP inferred_type_count ALL;
total_count = FOREACH grpd_inf_type_count_all GENERATESUM(inferred_type_count.count) AS tot_sum,MAX(inferred_type_count.count) AS max_val;
percentage = FOREACH inferred_type_count GENERATE inferred_type AStype, count AS total_cnt,CONCAT((Chararray)ROUND(count*100.0/total_count.tot_sum),'%') ASpercent,(count==total_count.max_val?'Dominant':'Other') ASinferred_dominant_other_datatype;
percentage_ord = ORDER percentage BYinferred_dominant_other_datatype ASC;

/*
CustomDatatypeInfererStorage UDF extends the StoreFunc. All the abstract methods have been overridden to implement logic that writes the contents of the relation into a file in a custom report like format.
The results are stored on the HDFS in the directory datatype_inferer
*/
STORE percentage_ord INTO'/user/cloudera/pdp/output/data_profiling/datatype_inferer'using com.profiler.CustomDatatypeInfererStorage('cust_id','chararray');

Java UDF

以下是 Java UDF 的代码片段:

@Override
  public String exec(Tuple tuples) throws IOException {

    String value = (String) tuples.get(0);
    String inferredType = null;
    try {
/*if tuples.get(0) is null it returns null else invokes getDataType() method to infer the datatype
      */
      inferredType = value != null ? getDataType(value) : NULL;

    } catch (Exception e) {
      e.printStackTrace();
  }
    // returns inferred datatype of the input value
    return inferredType;

结果

以下是将设计模式应用于交易数据的结果:

Column Name :  cust_id
Defined Datatype :  chararray
Inferred Dominant Datatype(s):  int, Count: 817740 Percentage: 100% 

在之前的结果中,对输入数据列cust_id进行了评估,以检查该值是否准确反映了定义的数据类型。在摄取阶段,数据类型被定义为chararray。通过使用数据来推断设计模式,cust_id列中的值的数据类型被推断为整数。

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • Chapter3/code/
  • Chapter3/datasets/

基本统计分析模式

本节描述了基本的统计分析设计模式,其中我们使用 Pig 脚本来应用统计函数来捕获关于数据质量的重要信息。

背景

之前的设计模式描述了一种推断数据类型的方法。数据分析过程的下一个逻辑步骤是评估值的质量测量。这是通过应用统计方法收集和分析数据来实现的。这些统计数据提供了数据对特定分析问题的适用性的高级概述,并揭示了数据生命周期管理早期阶段的潜在问题。

动机

基本统计分析设计模式有助于创建数据质量元数据,包括平均值、中值、模式、最大值、最小值和标准差等基本统计数据。这些统计数据为您提供了整个数据领域的完整快照,随着时间的推移跟踪这些统计数据将有助于您深入了解 Hadoop 集群正在接收的新数据的特征。在将新数据引入 Hadoop 之前,可以检查新数据的基本统计信息,提前警告不一致的数据,帮助防止添加低质量的数据。

该设计模式试图解决以下总结要求:

  • 范围分析方法扫描这些值,并确定数据是否要进行整体排序,还确定这些值是否被约束在一个定义明确的范围内。
  • 您可以评估数据的稀疏度来找到未填充元素的百分比。
  • 数据集的基数可以通过找出数据中出现的不同值的个数来分析。
  • 可以评估的唯一性,以确定分配给属性的每个值是否确实是排他的。
  • 可以评估数据过载以检查属性是否被用于各种目的。
  • 格式评估可以通过将无法识别的数据解析为已定义的格式来完成。

用例

以下是可以应用基本统计概要设计模式的用例:

  • 这种设计模式可以用来检测数据集中的异常,并通过对数据集中的值进行经验分析来发现意外行为。该模式检查记录数据的频率分布、方差、百分比及其与数据集的关系,以揭示潜在的缺陷数据值。
  • 可以使用这种设计模式的一个常见用例是,将数据从仍在使用的遗留数据源吸收到 Hadoop 集群中。在大型机等遗留系统中,大型机程序员在数据创建期间设计快捷方式和代码,并为不再使用或理解的不同目的重新加载特定字段。当这些数据被吸收到 Hadoop 中时,基本的统计设计模式可以帮助发现这个问题。

模式实现

这个设计模式在 Pig 中实现为一个独立的脚本,内部使用一个宏来传递参数和检索答案。拉丁语有一组Math函数,可以直接应用于一列数据。首先将数据加载到 Pig 关系中,然后将该关系作为参数传递给getProfile宏。宏迭代关系并将Math函数应用于每一列。getProfile宏设计模块化,可以应用于各种数据集,更好地理解数据汇总。

代码片段

为了解释这个模型是如何工作的,我们考虑存储在 HDFS 的零售交易数据集。包括Transaction IDTransaction dateCustomer IDPhone NumberProductProduct subclassProduct IDSales PriceCountry Code等属性。对于这个模式,我们将分析属性Sales Price的值。

PIG

下面是 Pig 脚本,说明了这个模式的实现:

/*
Register the datafu and custom storage jar files
*/
REGISTER '/home/cloudera/pdp/jars/datafu.jar';
REGISTER '/home/cloudera/pdp/jars/customprofilestorage.jar';

/*
Import macro defined in the file numerical_profiler_macro.pig
*/
IMPORT '/home/cloudera/pdp/data_profiling/numerical_profiler_macro.pig';

/*
Load the transactions dataset into the relation transactions
*/
transactions = LOAD'/user/cloudera/pdp/datasets/data_profiling/transactions.csv'USING  PigStorage(',') AS (transaction_id:long,transaction_date:datetime, cust_id:long, age:chararray,area:chararray, prod_subclass:int, prod_id:long, amt:int,asset:int, sales_price:int, phone_no:chararray,country_code:chararray);

/*
Use SAMPLE operator to pick a subset of the data, at most 20% of the data is returned as a sample
*/
sample_transactions = SAMPLE transactions 0.2;

/*
Invoke the macro getProfile with the parameters sample_transactions which contains a sample of the dataset and the column name on which the numerical profiling has to be done.
The macro performs numerical profiling on the sales_price column and returns various statistics like variance, standard deviation, row count, null count, distinct count and mode
*/
result =  getProfile(sample_transactions,'sales_price');

/*
CustomProfileStorage UDF extends the StoreFunc. All the abstract methods have been overridden to implement logic that writes the contents of the relation into a file in a custom report like format.
The results are stored on the HDFS in the directory numeric
*/
STORE result INTO'/user/cloudera/pdp/output/data_profiling/numeric' USINGcom.profiler.CustomProfileStorage();

下面是一个 Pig 脚本,展示了 getProfile宏的实现:

/*
Define alias VAR for the function datafu.pig.stats.VAR
*/
DEFINE VAR datafu.pig.stats.VAR(); 

/*
Define the macro, specify the input parameters and the return value
*/
DEFINE getProfile(data,columnName) returns numerical_profile{

/*
Calculate the variance, standard deviation, row count, null count and distinct count for the column sales_price
*/
data_grpd = GROUP $data ALL;
numerical_stats = FOREACH data_grpd  
{
  variance = VAR($data.$columnName);
  stdDeviation = SQRT(variance);
  rowCount = COUNT_STAR($data.$columnName);
  nullCount = COUNT($data.$columnName);
  uniq = DISTINCT $data.$columnName;
  GENERATE 'Column Name','$columnName' AS colName,'Row Count',rowCount,'Null Count' , (rowCount - nullCount),'Distinct Count',COUNT(uniq),'Highest Value',MAX($data.$columnName) AS max_numerical_count,'Lowest Value',MIN($data.$columnName) ASmin_numerical_count, 'Total Value',SUM($data.$columnName) AStotal_numerical_count,'Mean Value', AVG($data.$columnName) ASavg_numerical_count,'Variance',variance AS 	variance,'StandardDeviation', stdDeviation AS stdDeviation,'Mode' asmodeName,'NONE' as modevalue;
}

/*
Compute the mode of the column sales_price
*/
groupd = GROUP $data BY $columnName;
groupd_count = FOREACH groupd GENERATE 'Mode' as modeName, groupAS mode_values, (long) COUNT($data) AS total;
groupd_count_all = GROUP groupd_count ALL;
frequency = FOREACH groupd_count_all GENERATEMAX(groupd_count.total) AS fq;
filterd = FILTER groupd_count BY (total== frequency.fq AND total>1AND mode_values IS NOT NULL);
mode  = GROUP filterd BY modeName;

/*
Join relations numerical stats and mode. Return these values
*/
$numerical_profile = JOIN numerical_stats BY modeName FULL,mode BY group;
};

结果

通过使用基本统计分析模型,获得以下结果:

Column Name: sales_price
Row Count: 163794
Null Count: 0
Distinct Count: 1446
Highest Value: 70589
Lowest Value: 1
Total Value: 21781793
Mean Value: 132.98285040966093
Variance: 183789.18332067598
Standard Deviation: 428.7064069041609
Mode: 99

前面的结果总结了数据属性、行计数、空计数和不同值的数量。我们也知道数据在中心趋势和偏差方面的关键特征。均值和模式是衡量中心趋势的几个指标;方差是理解数据偏差的一种方法。

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • Chapter3/code/
  • Chapter3/datasets/

模式匹配模式

这部分描述了模式匹配设计模式,其中我们使用 Pig 脚本来匹配数字和文本模式,以确定数据是否与自身相关,从而获得数据质量的度量。

背景

在企业的上下文中,检查数据的一致性是在数据被摄取并确定其完整性和正确性之后。给定属性的值可以有不同的形状和大小。对于需要手动输入的字段尤其如此,在这些字段中,值是根据用户的意愿输入的。假设代表电话号码字段的列是连贯的,可以说所有的值都代表有效的电话号码,因为它们匹配预期的格式、长度和数据类型(号码),从而满足系统的预期。以不正确的格式虚报数据将导致不准确的分析。在大数据环境下,庞大的数据量会放大这种不准确性。

动机

从模式匹配的角度分析数据,衡量数据的一致性以及与预期模式匹配的数据量。该分析过程将这些值与一组预定义的可能值进行比较,以找出这些值是否与其自身一致。它抓住了数据的本质,并告诉您一个字段是完全数字的还是具有相同的长度。它还提供特定于数据格式的其他信息。评估是通过将无法识别的数据解析为定义的格式来完成的。基于模式分析和使用,识别数据的抽象类型以执行语义数据类型关联。在分析周期的早期阶段识别不匹配模式的百分比不准确性可以确保更好的数据清理并减少工作量。

用例

这个设计模式可以用来分析应该与特定模式匹配的数字或字符串数据。

模式实现

这个设计模式在 Pig 中作为独立脚本实现。该脚本试图通过分析存储在属性中的数据字符串来发现数据中的模式和常见记录类型。它生成几个与属性中的值匹配的模式,并报告每个候选模式后的数据百分比。该脚本主要执行以下任务:

  • 从元组中发现模式;每一个的数量和百分比。
  • 检查发现的模式,并将其分类为有效或无效。

代码片段

为了解释这个模型是如何工作的,我们考虑存储在 HDFS 的零售交易数据集。包含 T0、T1、T2、T3、T4、T5、T6、T7、T8 等属性。对于这个模式,我们感兴趣的是属性Phone Number的值。

PIG

下面是一个 Pig 脚本,说明了这种模式的实现:

/*
Import macro defined in the file pattern_matching_macro.pig
*/
IMPORT '/home/cloudera/pdp/data_profiling/pattern_matching_macro.pig';

/*
Load the dataset transactions.csv into the relation transactions
*/
transactions = LOAD'/user/cloudera/pdp/datasets/data_profiling/transactions.csv'USING  PigStorage(',') AS (transaction_id:long,transaction_date:datetime, cust_id:long, age:chararray,area:chararray, prod_subclass:int, prod_id:long, amt:int,asset:int, sales_price:int, phone_no:chararray,country_code:chararray);

/*
Invoke the macro and pass the relation transactions and the column phone_no as parameters to it.
The pattern matching is performed on the column that is passed.
This macro returns the phone number pattern, its count and the percentage
*/
result = getPatterns(transactions, 'phone_no');

/*
Split the relation result into the relation valid_pattern if the phone number pattern matches any of the two regular expressions. The patterns that do not match any of the regex are stored into the relation invalid_patterns
*/
SPLIT result INTO valid_patterns IF (phone_number MATCHES'([0-9]{3}-[0-9]{3}-[0-9]{4})' or phone_number MATCHES'([0-9]{10})'), invalid_patterns OTHERWISE;

/*
The results are stored on the HDFS in the directories valid_patterns and invalid_patterns
*/
STORE valid_patterns INTO '/user/cloudera/pdp/output/data_profiling/pattern_matching/valid_patterns';
STORE invalid_patterns INTO '/user/cloudera/pdp/output/data_profiling/pattern_matching/invalid_patterns';

以下是显示getPatterns宏实现的 PIG 脚本:

/*
Define the macro, specify the input parameters and the return value
*/
DEFINE getPatterns(data,phone_no) returns percentage{

/*
Iterate over each row of the phone_no column and transform each value by replacing all digits with 9 and all alphabets with a to form uniform patterns
*/
transactions_replaced = FOREACH $data  
{
  replace_digits = REPLACE($phone_no,'\\d','9');
  replace_alphabets = REPLACE(replace_digits,'[a-zA-Z]','a');
  replace_spaces = REPLACE(replace_alphabets,'\\s','');
  GENERATE replace_spaces AS phone_number_pattern;
}
/*
Group by phone_number_pattern and calculate count of each pattern
*/
grpd_ph_no_pattern = GROUP transactions_replaced BYphone_number_pattern;
phone_num_count = FOREACH grpd_ph_no_pattern GENERATE group asphone_num, COUNT(transactions_replaced.phone_number_pattern) ASphone_count;

/*
Compute the total count and percentage.
Return the relation percentage with the fields phone number pattern, count and the rounded percentage
*/
grpd_ph_no_cnt_all = GROUP phone_num_count ALL;
total_count = FOREACH grpd_ph_no_cnt_all GENERATESUM(phone_num_count.phone_count) AS tot_sum;
$percentage = FOREACH phone_num_count GENERATE phone_num asphone_number, phone_count as phone_number_count,CONCAT((Chararray)ROUND(phone_count*100.0/total_count.tot_sum),'%') as percent;
};

结果

以下是将设计模式应用于交易数据的结果。结果存储在文件夹valid_patternsinvalid_patterns中。

文件夹valid_patterns中的输出如下:

9999999999  490644    60%
999-999-9999  196257    24%

文件夹invalid_patterns中的输出如下:

99999         8177  1%
aaaaaaaaaa  40887  5%
999-999-999a  40888  5%
aaa-aaa-aaaa  40887  5%

先前的结果给出了我们数据集中所有电话号码模式的快照,它们的计数和百分比。利用这些数据,我们可以确定数据集中不准确数据的百分比,并在数据清理阶段采取必要的措施。因为 999-999-9999 格式的电话号码具有较高的相对频率,并且它是有效的模式,所以您可以导出一个规则,该规则要求该属性中的所有值都符合该模式。此规则可应用于数据清理阶段。

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • Chapter3/code/
  • Chapter3/datasets/

字符串分析模式

本节描述字符串分析的设计模式,其中我们使用文本数据的 Pig 脚本来学习重要的统计信息。

背景

大多数大数据实现处理嵌入在列中的文本数据。为了从这些列中获得洞察力,它们必须与其他企业结构化数据集成。这种设计模式说明了一些有助于理解文本数据质量的方法。

动机

文本的质量可以通过对属性值应用基本的统计技术来确定。在为目标系统选择合适的数据类型和大小时,找到字符串的长度是最重要的方面。您可以使用最大和最小字符串长度来确定 Hadoop 接收的数据是否满足给定的约束。当处理 petabyte 范围内的数据时,将字符数量限制得足够大可以通过减少不必要的存储空间来优化存储和计算。

使用字符串长度,还可以确定一列中每个字符串的不同长度,以及每个长度在表格中所代表的行数百分比。

例如,代表美国州代码的列的配置文件应该是两个字符,但是如果收集的配置文件显示的值不同于两个字符,则表明该列中的值不一致。

用例

这种模式可以应用于主要包含文本数据类型的数据列,以找出文本是否在定义的约束内。

模式实现

这个设计模式在 Pig 中实现为一个独立的脚本,它使用一个宏在内部检索概要文件。Pig Latin 有一组可以直接应用于一列数据的数学函数。首先将数据加载到 Pig 关系transactions中,然后将该关系作为参数传递给getStringProfile宏。宏迭代关系并将Math函数应用于每个值。getStringProfile宏被设计成模块化的,可以跨各种文本列应用,以更好地理解字符串数据的摘要。

代码片段

为了说明 T10 模型的工作原理,我们考虑存储在 HDFS 的零售交易数据集。包含 T0、T1、T2、T3、T4、T5、T6、T7、T8 等属性。对于这个模式,我们感兴趣的是属性Country Code的值。

PIG

下面是一个 Pig 脚本,说明了这种模式的实现:

/*
Register the datafu and custom storage jar files
*/
REGISTER '/home/cloudera/pdp/jars/datafu.jar';
REGISTER '/home/cloudera/pdp/jars/customprofilestorage.jar';

/*
Import macro defined in the file string_profiler_macro.pig
*/
IMPORT'/home/cloudera/pdp/data_profiling/string_profiler_macro.pig';

/*
Load the transactions dataset into the relation transactions
*/
transactions = LOAD'/user/cloudera/pdp/datasets/data_profiling/transactions.csv'using PigStorage(',') as(transaction_id:long,transaction_date:datetime, cust_id:long,age:chararray, area:chararray, prod_subclass:int, prod_id:long,amt:int, asset:int, sales_price:int, phone_no:chararray,country_code:chararray);
/*
Invoke the macro getStringProfile with the parameters transactions and the column name on which the string profiling has to be done.
The macro performs string profiling on the country_code column and returns various statistics like row count, null count, total character count, word count, identifies distinct country codes in the dataset and calculates their count and percentage.
*/
result =  getStringProfile(transactions,'country_code');

/*
CustomProfileStorage UDF extends the StoreFunc. All the abstract methods have been overridden to implement logic that writes the contents of the relation into a file in a custom report like format.
The results are stored on the HDFS in the directory string
*/
STORE result INTO'/user/cloudera/pdp/output/data_profiling/string' USINGcom.profiler.CustomProfileStorage();

以下是【T1】 Pig 脚本,展示了getStringProfile宏的实现:

/*
Define the macro, specify the input parameters and the return value
*/
DEFINE getStringProfile(data,columnName) returns string_profile{

/*
Calculate row count and null count on the column country_code
*/
data_grpd = GROUP $data ALL;
string_stats = FOREACH data_grpd  
{
  rowCount = COUNT_STAR($data.$columnName);
  nullCount = COUNT($data.$columnName);
  GENERATE 'Column Name','$columnName' AS colName,'Row Count',rowCount,'Null Count' ,(rowCount - nullCount),'Distinct Values' as dist,'NONE' as distvalue;
}

/*
Calculate total char count, max chars, min chars, avg chars on the column country_code
*/
size = FOREACH $data GENERATE SIZE($columnName) AS chars_count;
size_grpd_all = GROUP size ALL;
char_stats = FOREACH size_grpd_all GENERATE 'Total CharCount',SUM(size.chars_count) AS total_char_count,'Max Chars',MAX(size.chars_count) AS max_chars_count,'Min Chars',MIN(size.chars_count) AS min_chars_count,'Avg Chars',AVG(size.chars_count) AS avg_chars_count,'Distinct Values' asdist,'NONE' as distvalue;

/*
Calculate total word count, max words and min words on the column country_code
*/
words = FOREACH $data GENERATE FLATTEN(TOKENIZE($columnName)) ASword;
whitespace_filtrd_words = FILTER words BY word MATCHES '\\w+';
grouped_words = GROUP whitespace_filtrd_words BY word;
word_count = FOREACH grouped_words GENERATECOUNT(whitespace_filtrd_words) AS count, group AS word;
word_count_grpd_all = GROUP word_count ALL;
words_stats = FOREACH word_count_grpd_all GENERATE 'WordCount',SUM(word_count.count) AS total_word_count,'Max Words',MAX(word_count.count) AS max_count,'Min Words',MIN(word_count.count) AS min_count,'Distinct Values'as dist,'NONE' as distvalue;

/*
Identify distinct country codes and their count
*/
grpd_data = GROUP $data BY $columnName;
grpd_data_count = FOREACH grpd_data GENERATE group ascountry_code, COUNT($data.$columnName) AS country_count;

/*
Calculate the total sum of all the counts
*/
grpd_data_cnt_all = GROUP grpd_data_count ALL;
total_count = FOREACH grpd_data_cnt_all GENERATESUM(grpd_data_count.country_count) AS tot_sum;

/*
Calculate the percentage of the distinct country codes
*/
percentage = FOREACH grpd_data_count GENERATE country_code ascountry_code, 
country_count as country_code_cnt,ROUND(country_count*100.0/total_count.tot_sum) aspercent,'Distinct Values' as dist;

/*
Join string stats, char_stats, word_stats and the relation with distinct country codes, their count and the rounded percentage. Return these values
*/
percentage_grpd = GROUP percentage BY dist;
$string_profile = JOIN string_stats BY dist,char_stats BY dist ,words_stats BY dist, percentage_grpd BY group;
};

结果

使用字符串分析模式,可以获得以下结果:

Column Name: country_code
Row Count: 817740
Null Count: 0
Total Char Count: 5632733
Max Chars: 24
Min Chars: 2
Avg Chars: 6.888171056815125
Word Count: 999583
Max Words: 181817
Min Words: 90723

Distinct Values
country_code      Count    Percentage
US          181792    22%
U.S	        90687    11%
USA	        181782    22%
U.S.A        90733    11%
America        90929    11%
United States      91094    11%
United States of America  90723    11%

前面的结果总结了数据属性,如行数、空值数和字符总数。Max charsMin chars计数可以通过检查数值的长度是否在范围内来验证数据质量。根据元数据,国家代码的有效值应为两个字符,但结果显示最大字符数为24,这意味着数据不准确。Distinct values部分的结果显示了数据集中不同的国家代码,以及它们的计数和百分比。利用这些结果,我们可以确定数据集中不准确数据的百分比,并在数据清理阶段采取必要的措施。

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • Chapter3/code/
  • Chapter3/datasets/

非结构化文本解析模式

本节描述了非结构化文本分析的设计模式,其中我们使用 Pig 脚本来学习自由格式文本数据的重要统计信息。

背景

文本挖掘基于 Hadoop 拍摄的非结构化数据,从无意义的数据块中提取有趣且非琐碎的有意义的模式。文本挖掘是一个跨学科的领域,它利用信息检索、数据挖掘、机器学习、统计学和计算语言学从文本中提取有意义的模式。通常,Hadoop 的并行处理能力用于处理大量文本数据、文档分类、推文聚类、本体构建、实体提取、情感分析等。

该模型讨论了一种利用文本预处理技术来确定文本数据质量的方法,如停止词去除、词干和 TF-IDF。

动机

非结构化文本本质上是不一致的,会导致分析不准确。文本中的不一致是因为表达一个想法的方式有很多。

文本预处理提高了数据质量,提高了分析的准确性,降低了文本挖掘过程的难度。以下是完成文本预处理的步骤:

  • 文本预处理的第一步是将文本块转换成标签,以删除标点符号、连字符、括号等。,并且只保留有意义的关键字、缩写和首字母缩略词以供进一步处理。标记涉及文档一致性的度量,因为被消除的无意义标记的数量和数据相对于自身的不一致性之间存在线性比例关系。
  • 去词是文本预处理的下一个逻辑步骤。此步骤包括删除不为文档提供任何含义或上下文的单词。这些单词叫做 stopword 。它们通常包含代词、冠词、介词等。在实际从原始文本中删除它们之前,将定义一个停用词列表。该列表可以包括特定于特定领域的其他单词。
  • 词干步骤通过将一个单词移除或转换成它的基本单词(词干),将单词的各种形式简化成它的词根形式。例如,同意、同意、不同意、同意和不同意(取决于特定的词干算法)被词干化为同意。这样做是为了使语料库中的所有标签一致。
  • 词干处理完成后,通过计算词频,相对于出现频率为标签分配权重。此统计数据表示单词在文档中出现的次数。计算逆文档频率,知道单词在所有文档中出现的频率。这个统计数据决定了一个词在所有文档中是常见还是罕见。查找单词的频率和反向文档的频率对文本的质量有影响,因为这些统计数据会根据单词对文档或语料库的重要性来告诉您是否可以丢弃或使用它们。

用例

这种设计模式可以用于需要通过文本预处理技术了解非结构化文本语料库质量的情况。这种设计模式并不详尽,它涵盖了文本预处理的几个重要方面及其对数据分析的适用性。

模式实现

这个设计模式在 Pig 中作为独立脚本实现。内部使用unstructuredtextprofiling Java UDF 执行词干,生成词频和逆文档词频。该脚本执行右连接来移除停止字。Stopword 列表首先从外部文本文件加载到关系中,然后在外部连接中使用。

词干是使用unstructuredtextprofiling JAR 文件中实现的波特斯特梅尔算法完成的。

代码片段

为了演示这种模式是如何工作的,我们考虑维基百科的文本语料库,它存储在 HDFS 可以访问的文件夹中。这个样本语料库由与计算机科学和信息技术相关的维基页面组成。

PIG

下面是一个 Pig 脚本,说明了这种模式的实现:

/*
Register custom text profiler jar
*/
REGISTER '/home/cloudera/pdp/jars/unstructuredtextprofiler.jar';

/*
Load stop words into the relation stop_words_list
*/
stop_words_list = LOAD'/user/cloudera/pdp/datasets/data_profiling/text/stopwords.txt'USING PigStorage();

/*
Tokenize the stopwords to extract the words
*/
stopwords = FOREACH stop_words_list GENERATEFLATTEN(TOKENIZE($0));

/*
Load the dataset into the relations doc1 and doc2.
Tokenize to extract the words for each of these documents
*/
doc1 = LOAD'/user/cloudera/pdp/datasets/data_profiling/text/computer_science.txt' AS (words:chararray);
docWords1 = FOREACH doc1 GENERATE 'computer_science.txt' ASdocumentId, FLATTEN(TOKENIZE(words)) AS word;
doc2 = LOAD'/user/cloudera/pdp/datasets/data_profiling/text/information_technology.txt' AS (words:chararray);
docWords2 = FOREACH doc2 GENERATE 'information_technology.txt' ASdocumentId, FLATTEN(TOKENIZE(words)) AS word;

/*
Combine the relations using the UNION operator
*/
combined_docs = UNION docWords1, docWords2;

/*
Perform pre-processing by doing the following
Convert the data into lowercase
Remove stopwords
Perform stemming by calling custom UDF. it uses porter stemmer algorithm to perform stemming
*/
lowercase_data = FOREACH combined_docs GENERATE documentId asdocumentId, FLATTEN(TOKENIZE(LOWER($1))) as word;
joind = JOIN stopwords BY $0 RIGHT OUTER, lowercase_data BY $1;
stop_words_removed = FILTER joind BY $0 IS NULL;
processed_data = FOREACH stop_words_removed GENERATE documentId asdocumentId, com.profiler.unstructuredtextprofiling.Stemmer($2)as word;

/*
Calculate word count per word/doc combination using the Group and FOREACH statement and the result is stored in word_count
*/
grpd_processed_data = GROUP processed_data BY (word, documentId);
word_count = FOREACH grpd_processed_data GENERATE group ASwordDoc,COUNT(processed_data) AS wordCount;

/*
Calculate Total word count per document using the Group and FOREACH statement and the result is stored in total_docs_wc
*/
grpd_wc = GROUP word_count BY wordDoc.documentId;
grpd_wc_all = GROUP grpd_wc ALL;
total_docs = FOREACH grpd_wc_all GENERATEFLATTEN(grpd_wc),COUNT(grpd_wc) AS totalDocs;
total_docs_wc = FOREACH total_docs GENERATEFLATTEN(word_count),SUM(word_count.wordCount) AS wordCountPerDoc,totalDocs;

/*
Calculate Total document count per word is using the Group and FOREACH statement and the result is stored in doc_count_per_word 
*/
grpd_total_docs_wc = GROUP total_docs_wc BY wordDoc.word;
doc_count_per_word = FOREACH grpd_total_docs_wc GENERATEFLATTEN(total_docs_wc),COUNT(total_docs_wc) AS docCountPerWord;

/*
Calculate tfidf by invoking custom Java UDF.
The overall relevancy of a document with respect to a term is computed and the resultant data is stored in gen_tfidf
*/
gen_tfidf = FOREACH doc_count_per_word GENERATE $0.word AS word,$0.documentId AS documentId,com.profiler.unstructuredtextprofiling.GenerateTFIDF(wordCount,wordCountPerDoc,totalDocs,docCountPerWord) AS tfidf;

/*
Order by relevancy
*/
orderd_tfidf = ORDER gen_tfidf BY word ASC, tfidf DESC;

/*
The results are stored on the HDFS in the directory tfidf
*/
STORE orderd_tfidf into'/user/cloudera/pdp/output/data_profiling/unstructured_text_profiling/tfidf';

爪哇 UDF 是炮泥。

以下是 Java UDF 的代码片段:

public String exec(Tuple input) throws IOException {
    //Few declarations go here
    Stemmer s = new Stemmer();
    //Code for exception handling goes here
    //Extract values from the input tuple
    String str = (String)input.get(0);

    /*
    Invoke the stem(str) method of the class Stemmer.
    It return the stemmed form of the word
    */
    return s.stem(str);
}         

TF-IDF 一代的爪哇 UDF

以下是用于计算 TF-IDF 的 Java UDF 代码片段:

public class GenerateTFIDF extends EvalFunc<Double>{
  @Override
  /**
  *The pre-calculated wordCount, wordCountPerDoc, totalDocs and docCountPerWord are passed as parameters to this UDF.
  */
  public Double exec(Tuple input) throws IOException {
    /*
    Retrieve the values from the input tuple
    */
    long countOfWords = (Long) input.get(0);
    long countOfWordsPerDoc = (Long) input.get(1);
    long noOfDocs = (Long) input.get(2);
    long docCountPerWord = (Long) input.get(3);
    /*
    Compute the overall relevancy of a document with respect to a term. 
    */
    double tf = (countOfWords * 1.0) / countOfWordsPerDoc;
    double idf = Math.log((noOfDocs * 1.0) / docCountPerWord);
    return tf * idf;
  }
} 

结果

以下是将设计模式应用于 computer_scienceinformation_technology维基文本语料库的结果:

associat  information_technology.txt  0.0015489322470613302
author  information_technology.txt  7.744661235306651E-4
automat  computer_science.txt  8.943834587870262E-4
avail  computer_science.txt  0.0
avail  information_technology.txt  0.0
babbag  computer_science.txt  8.943834587870262E-4
babbage'  computer_science.txt  0.0026831503763610786
base  information_technology.txt  0.0
base  computer_science.txt  0.0
base.  computer_science.txt  8.943834587870262E-4
basic  information_technology.txt  7.744661235306651E-4
complex.  computer_science.txt  8.943834587870262E-4
compon  information_technology.txt  0.0015489322470613302
compsci  computer_science.txt  8.943834587870262E-4
comput  computer_science.txt  0.0
comput  information_technology.txt  0.0
computation  computer_science.txt  8.943834587870262E-4
computation.  computer_science.txt  8.943834587870262E-4
distinguish  information_technology.txt  7.744661235306651E-4
distribut	computer_science.txt  0.0
distribut	information_technology.txt  0.0
divid  computer_science.txt  8.943834587870262E-4
division.  computer_science.txt  8.943834587870262E-4
document  information_technology.txt  7.744661235306651E-4
encompass  information_technology.txt  7.744661235306651E-4
engin  computer_science.txt  0.0035775338351481047
engine.[5]  computer_science.txt  8.943834587870262E-4
enigma  computer_science.txt  8.943834587870262E-4
enough  computer_science.txt  0.0017887669175740523
enterprise.[2]  information_technology.txt  7.744661235306651E-4
entertain  computer_science.txt  8.943834587870262E-4

原文经过停词和词干提取阶段,然后计算词频-逆文档频率。结果显示单词、它所属的文档和 TF-IDF。TF-IDF 较高的单词意味着它们与其出现的文档有很强的关系,而 TF-IDF 较低的单词被认为质量较低,可以忽略。

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • Chapter3/code/
  • Chapter3/datasets/

总结

本章以第二章数据接收输出模式所学知识为基础。在本章中,我们将来自多个源系统的数据进行集成,并将其接收到 Hadoop 中。下一步是通过查看组件值来找到关于数据类型的线索。检查这些值,查看它们是否被曲解,它们的单位是否被曲解,或者单位的上下文是否被错误导出。这种调查机制将在数据类型推断模型中详细讨论。

在基本统计分析模式下,我们收集数值的统计信息,检查这些数值是否满足用例的质量预期,从而找到以下问题的答案:对于数值字段,所有数值都是数值吗?可枚举字段的所有值都属于正确的集合吗?字段是否满足范围约束?它们完整吗?,等等。

模式匹配设计模式探索了一些通过数据类型、数据长度和正则表达式模式来度量数字和文本列数据集的一致性的技术。下一个模式通过使用各种统计方法揭示了表示字符串值的列的质量度量。这将在字符串分析设计模式中详细解释。非结构化文本分析设计模式试图形式化文本预处理技术(如停止词移除、词干分析和 TF-IDF 计算)来理解非结构化文本的质量。

在下一章中,我们将重点关注可以应用于各种数据格式的数据验证和清理模式。阅读本章后,观众将能够使用约束检查和正则表达式匹配等技术选择正确的模式来验证数据的准确性和完整性。我们还将在下一章讨论数据清理技术,如过滤器和统计清理。

四、数据验证和清理模式

在前一章中,您已经学习了与数据分析相关的各种模式。通过这些模式,您已经了解了获取 Hadoop 集群中数据的属性、内容、上下文、结构和条件等重要信息的不同方法。在开始将数据清理成更有用的形式之前,将这些数据分析模式应用于数据生命周期。

本章涵盖以下设计模式:

  • 约束验证和清理模式:这说明数据是根据一组约束进行验证,检查是否有缺失值,这些值是否在业务规则规定的范围内,或者这些值是否符合参照完整性和唯一性约束。根据业务规则,要么删除无效记录,要么对无效数据应用适当的清理步骤。
  • regex 验证和清理模式:这演示了通过使用正则表达式和基于模式的记录过滤来验证数据,以特定模式或长度匹配数据来清理无效数据。
  • 损坏数据验证和清理模式:这为从各种来源了解数据损坏设置了上下文。该模型详细解释了噪声和异常值对数据的影响以及检测和清除它们的方法。
  • 非结构化文本数据验证和清洗模式:这展示了通过执行预处理步骤,如小写转换、停止词移除、词干移除、标点符号移除、额外空间移除、数字识别和拼写错误识别来验证和清洗非结构化数据语料库的方法。

大数据的数据验证和清理

数据验证和清理过程检测并删除数据中不正确的记录。数据验证和清理的过程确保在数据用于分析过程之前,可以很好地识别数据中的不一致性。然后替换、修改或删除不一致的数据,使其更加一致。

大多数数据验证和清理都是通过基于模式分析静态约束来执行的。组合约束检查模式将告诉我们缺失值、空值、模糊表示、外键约束等的存在。

从大数据的角度来看,数据验证和清理在获取价值方面发挥着越来越重要的作用。清理大数据时,需要考虑的最大权衡之一是时间质量权衡。给定无限的时间,我们可以提高坏数据的质量,但设计一个好的数据清理脚本的挑战是在时限内覆盖尽可能多的数据并成功清理。

在典型的大数据用例中,不同类型数据的集成会增加清理过程的复杂性。来自联邦系统的高维数据有自己的清理方法,而大量纵向数据的清理方法是不同的。流式数据可以是时间序列数据,可以通过实时清洗的方式代替批量清洗机制进行有效处理。必须使用文本预处理和清理方法来处理非结构化数据、描述性数据和 web 数据。

Hadoop 环境中的各种接触点可能会导致数据不良。以下要点概述了映射到这些接触点的常见清洁问题:

  • 数据采集导致的大数据清理问题:数据不一致可能是数据采集方式错误导致的。这些方法可以从手动输入到社交媒体数据(使用非标准单词)、输入重复数据和测量误差。
  • 数据传递不当导致的大数据清理:这可能是进入与 Hadoop 集成的上游系统后数据转换不当。数据传输不正确导致数据不良的原因包括聚合不正确、空值转换为默认值、缓冲区溢出和传输问题。
  • 数据存储问题导致的大数据清理问题:数据不一致可能是数据物理和逻辑存储问题的结果。物理存储导致的数据不一致是罕见的原因。这种情况发生在数据长时间存储并趋于损坏时,称为位损坏。将数据存储在逻辑存储结构中会导致以下问题:元数据不足、实体关系中缺少链接、缺少时间戳等。
  • 数据集成带来的大数据清洗问题:集成异构系统的数据对不良数据的贡献很大,通常会导致不一致字段相关的问题。不同的定义、不同的字段格式、不正确的时间同步和遗留数据的特征、错误的处理算法都会导致这种情况。

一般来说,验证和清理大数据的第一步是用各种数学技术探索数据,以检测数据中是否有任何不准确之处。这一初步探索是通过了解每个属性的数据类型和域、其上下文、可接受的值等来完成的。之后,核实实际数据,验证是否符合可接受的限值。这给出了不准确特征及其位置的初步估计。在验证阶段,我们可以通过指定预期约束来执行这一探索活动,以查找和过滤不符合预期约束的数据,然后在清理步骤中对数据采取所需的操作。

在我们探索数据并发现异常之后,一系列数据清理例程将迭代运行。这些数据清理例程参考主数据和相关业务规则来执行清理,并获得更高质量数据的最终结果。数据清理例程通过填充缺失值、平滑有噪声的数据、识别或移除异常值以及解决不一致来清理数据。在执行清洗之后,执行可选的控制步骤,其中评估结果,并且异常处理在清洗过程中未被校正的元组。

选择 PIG 进行验证和清洗。

在 Hadoop 环境中的 Pig 中实现验证和清理代码减少了时间和质量之间的权衡,以及将数据移动到外部系统以执行清理的需要。下图描述了实施的高级概述:

Choosing Pig for validation and cleansing

验证并清洗 PIG。

以下是在 Hadoop 环境下使用 Pig 进行数据清理的优势:

  • 由于验证和清洗是在同一环境中进行的,因此整体性能得到了提高。无需将数据传输到外部系统进行清理。
  • Pig 非常适合编写用于验证和清理脚本的代码,因为内置函数适合处理混乱的数据和探索性分析。
  • Pig 通过链接复杂的工作流实现了清洗过程的自动化,对于定期更新的数据集非常方便。

约束验证和清洁设计模式

约束验证和清理模式根据一套规则和技术处理验证数据,然后清理无效数据。

背景

约束告诉我们数据应该服从的属性。它们可以应用于整个数据库、表、列或整个模式。这些约束是在设计时创建的规则,用于防止数据被破坏并减少处理错误数据的开销。它们指定哪些值对数据有效。

约束,如空值检查和范围检查,可以用来知道在 Hadoop 中获得的数据是否有效。通常,Hadoop 中的约束验证和数据清理可以基于业务规则来执行,业务规则实际上决定了必须应用于特定数据子集的约束类型。

在给定列必须属于特定类型的情况下,将应用数据类型约束。当我们想要强制一个约束时,比如一个数字或日期应该落在一个指定的范围内,一个范围约束被应用。这些范围约束通常指定用于比较的最小值和最大值。约束强制执行硬验证规则,以确保一些重要字段不会保持为空,这本质上是检查空值或缺失值,并使用一系列方法来消除它们。成员约束强制执行数据值应该总是来自一组预定值的规则。

无效数据可能是从没有在 Hadoop 中实现软件约束的遗留系统接收数据的结果,也可能是从电子表格等来源接收数据的结果,在这些来源中,对用户选择在单元格中输入的内容设置约束相对困难。

动机

约束验证和清理设计模式实现了一个 Pig 脚本,它通过检查数据是否在特定、指定和强制的范围约束内来验证数据,然后进行清理。

有许多方法可以检查 Hadoop 中驻留的数据是否符合强制约束。最有用的方法之一是检查空值或缺失值。如果给定的一组数据中有缺失的值,了解这些缺失的值是否是数据质量不足的原因是很重要的,因为在很多情况下,数据中有缺失的值是可以的。

查找空值或缺失值相对简单,但是通过用适当的值填充它们来清除缺失值是一项复杂的任务,这通常取决于业务案例。

根据业务案例,空值可以被忽略或手动输入,作为清理过程的一部分,但这种方法是最不推荐的。对于分类变量,可以使用一个恒定的全局标签,如“XXXXX”来描述缺失的值。如果此标签不能与表中的其他现有值冲突,或者缺少的值可以由最频繁出现的值(模式)替换。根据数据分布,建议使用正态分布数据的平均值和偏斜分布数据的中值。平均值和中值的使用仅适用于数字数据类型。使用概率度量,如贝叶斯推理或决策树,可以比其他情况更准确地计算缺失值,但这是一种耗时的方法。

范围通过指定有效值的上限和下限来限制数据中可以使用的值。设计模式首先检查数据的有效性,并找出数据是否不在指定的范围内。通过过滤无效数据,按照业务规则清理无效数据,或者如果无效数据高于最大范围值,则用最大范围值替换无效值;相反,如果无效数据低于范围,无效值将被最小范围值替换。

唯一约束将值的存在限制为在整个表中唯一。这适用于重复值等于无效数据的主键。一个表可以有任意数量的唯一约束,主键被定义为其中之一。Hadoop 接收到数据后,我们可以使用这种设计模式进行验证,找出数据是否满足唯一约束,并通过删除重复项来清理。

用例

当您摄取大量结构化数据,并希望通过对照强制、范围和唯一约束验证数据来执行完整性检查,然后清理数据时,您可以使用这种设计模式。

模式实现

这种设计模式作为一个独立的脚本在 Pig 中实现。该脚本加载数据,并根据指定的约束对其进行验证。以下是模式如何实现的简要描述:

  • 强制约束:【T2】脚本检查不符合强制约束的无效和缺失数据,并通过用中值替换缺失值来移除缺失数据。
  • 范围约束 : 脚本定义了一个范围约束,说明claim_amount列的有效值应该在下限和上限之间。该脚本验证数据并找到该范围之外的所有值。在清洗步骤中,过滤这些值;它们还可以根据预定义的业务规则更新为范围的最小值和最大值。
  • 唯一约束:【T2】脚本执行检查以验证数据是否不同,然后通过删除重复值来清除数据。

代码片段

为了说明模式的工作原理,我们考虑一个存储在 HDFS 的汽车保险理赔数据集,它包含两个文件。automobile_policy_master.csv为主文件;它包含唯一的 ID、车辆详细信息、价格和支付的保费。主文件用于验证索赔文件中的数据。automobile_insurance_claims.csv文件包含汽车保险理赔数据,具体为车辆修理费理赔;包括CLAIM_IDPOLICY_MASTER_IDVEHICLE_DETAILSCLAIM_DETAILS等属性。对于该模式,我们将对CLAIM_AMOUNTPOLICY_MASTER_IDAGECITY进行约束验证和清理,如下代码所示:

/*
Register Datafu and custom jar files
*/
REGISTER '/home/cloudera/pdp/jars/datatypevalidationudf.jar';
REGISTER  '/home/cloudera/pdp/jars/datafu.jar';

/*
Define aliases for Quantile UDF from Datafu and custom UDF DataTypeValidationUDF.
The parameters to Quantile constructor specify list of quantiles to compute
The parameter to the DataTypeValidationUDF constructor specifies the Data type that would be used for validation
*/
DEFINE Quantile datafu.pig.stats.Quantile('0.25','0.5','0.75'); 
DEFINEDataTypeValidationUDF com.validation.DataTypeValidationUDF('double');

/*
Load automobile insurance claims data set into the relation claims and policy master data set into the relation policy_master
*/
claims = LOAD'/user/cloudera/pdp/datasets/data_validation/automobile_insurance_claims.csv' USING  PigStorage(',') AS(claim_id:chararray, policy_master_id:chararray,registration_no:chararray, engine_no:chararray,chassis_no:chararray,customer_id:int,age:int,first_name:chararray,last_name:chararray,street:chararray,address:chararray,  city:chararray,  zip:long,gender:chararray, claim_date:chararray,garage_city:chararray,bill_no:long,claim_amount:chararray,garage_name:chararray,claim_status:chararray);
policy_master = LOAD'/user/cloudera/pdp/datasets/data_validation/automobile_policy_master.csv' USING  PigStorage(',') AS(policy_master_id:chararray, model:int, make:chararray,price:double, premium:float);

/*
Remove duplicate tuples from the relation claims to ensure that the data meets unique constraint
*/
claims_distinct = DISTINCT claims;

/*
Invoke the custom DataTypeValidationUDF with the parameter claim_amount.
The UDF returns the tuples where claim_amount does not match the specified data type (double), these values are considered as invalid.
Invalid values are stored in the relation invalid_claims_amt
*/
claim_distinct_claim_amount = FOREACH claims_distinct GENERATEclaim_amount AS claim_amount;
invalid_c_amount = FOREACH claim_distinct_claim_amount GENERATEDataTypeValidationUDF(claim_amount) AS claim_amount;
invalid_claims_amt = FILTER invalid_c_amount BY claim_amount ISNOT NULL;

/*
Filter invalid values from the relation claims_distinct and segregate the valid and invalid claim amount
*/
valid_invalid_claims_amount_join = JOIN invalid_claims_amt BY claim_amount RIGHT, claims_distinct BY claim_amount;
valid_claims_amount = FILTER valid_invalid_claims_amount_join BY$0 IS NULL;
invalid_claims_amount = FILTER valid_invalid_claims_amount_join BY$0 IS NOT NULL;

/*
For each invalid_claims_amount, generate all the values and specify the reason for considering these values as invalid
*/
invalid_datatype_claims = FOREACH invalid_claims_amount GENERATE$1 AS claim_id,$2 AS policy_master_id, $3 AS registration_no,$4 AS engine_no, $5 AS chassis_no,$6 AS customer_id,$7 AS age,$8 AS first_name,$9 AS last_name, $10 AS street, $11 AS address,$12 AS city, $13 AS zip, $14 AS gender, $15 AS claim_date,$16 AS garage_city,$17 AS bill_no, $18 AS claim_amount,$19 ASgarage_name, $20 AS claim_status,'Invalid Datatype forclaim_amount' AS reason;

valid_datatype_claims = FOREACH valid_claims_amount GENERATE $1 ASclaim_id,$2 AS policy_master_id, $3 AS registration_no,$4 AS engine_no, $5 AS chassis_no,$6 AS customer_id,$7 AS age,$8 AS first_name,$9 AS last_name, $10 AS street, $11 AS address,$12 AS city, $13 AS zip, $14 AS gender, $15 AS claim_date,$16 AS garage_city,$17 AS bill_no, $18 AS claim_amount,$19 AS garage_name, $20 AS claim_status;

/*
Compute quantiles using Datafu's Quantile UDF
*/
groupd = GROUP valid_datatype_claims ALL;
quantiles = FOREACH groupd {
  sorted = ORDER valid_datatype_claims BY age;
  GENERATE Quantile(sorted.age) AS quant;
}

/*
Check for occurrence of null values for the column Age which is a numerical field and for city which is a categorical field.
The nulls in age column are replaced with median and the nulls in city column are replaced with a constant string XXXXX.
*/
claims_replaced_nulls = FOREACH valid_datatype_claims GENERATE $0,$1 ,$2 , $3 ,$4 , $5 ,(int) ($6 is null ? FLOOR(quantiles.quant.quantile_0_5) : $6) AS age, $7, $8 ,$9 , $10 ,($11 is null ? 'XXXXX' : $11) AS city, $12, $13 , $14 , $15 ,$16 ,(double)$17 , $18 ,$19;

/*
Ensure Referential integrity by checking if the policy_master_id in the claims dataset is present in the master dataset.
The values in the claims dataset that do not find a match in the master dataset are considered as invalid values and are removed.
*/
referential_integrity_check = JOIN claims_replaced_nulls BYpolicy_master_id, policy_master BY policy_master_id;
referential_integrity_invalid_data = JOIN policy_master BYpolicy_master_id RIGHT, claims_replaced_nulls BYpolicy_master_id;
referential_check_invalid_claims = FILTERreferential_integrity_invalid_data BY $0 IS NULL;

/*
For each referential_check_invalid_claims, generate all the values and specify the reason for considering these values as invalid
*/
invalid_referential_claims = FOREACHreferential_check_invalid_claims GENERATE  $5 ,$6, $7, $8 ,$9 ,$10 , $11, $12, $13 , $14 , $15 , $16 ,$17 , $18 ,$19,$20,  $21 ,(chararray) $22 , $23 ,$24,'Referential check Failed for policy_master_id' AS reason;

/*
Perform Range validation by checking if the values in the claim_amount column are within a range of 7% to 65% of the price in the master dataset.
The values that fall outside the range are considered as invalid values and are removed.
*/
referential_integrity_valid_claims = FILTERreferential_integrity_check BY( claims_replaced_nulls::claim_amount>=(policy_master::price*7/100) ANDclaims_replaced_nulls::claim_amount<=(policy_master::price*65/100 ));
valid_claims = FOREACH referential_integrity_valid_claims GENERATE$0, $1 ,$2 , $3 ,$4 , $5 ,$6 , $7, $8 ,$9 , $10 , $11 , $12,$13 , $14 , $15 , $16 ,$17 , $18 ,$19;
invalid_range = FILTER referential_integrity_check BY( claims_replaced_nulls::claim_amount<=(policy_master::price*7/100) ORclaims_replaced_nulls::claim_amount>=(policy_master::price*65/100 ));

/*
For each invalid_range, generate all the values and specify the reason for considering these values as invalid
*/
invalid_claims_range = FOREACH invalid_range GENERATE $0, $1 ,$2 ,$3 ,$4 , $5 ,$6, $7, $8 ,$9 , $10 , $11, $12, $13 , $14 , $15 ,$16 ,(chararray)$17 , $18 ,$19,'claim_amount not within range' AS reason;

/*
Combine all the relations containing invalid values. 
*/
invalid_claims = UNIONinvalid_datatype_claims,invalid_referential_claims,invalid_claims_range;

/*
The results are stored on the HDFS in the directories valid_data and invalid_data
The values that are not meeting the constraints are written to a file in the folder invalid_data. This file has an additional column specifying the reason for elimination of the record, this can be used for further analysis.
*/
STORE valid_claims INTO'/user/cloudera/pdp/output/data_validation_cleansing/constraints_validation_cleansing/valid_data';
STORE invalid_claims INTO'/user/cloudera/pdp/output/data_validation_cleansing/constraints_validation_cleansing/invalid_data';

结果

以下为原始数据集的片段;为了提高可读性,我们删除了一些列。

claim_id,policy_master_id,cust_id,age,city,claim_date,claim_amount
A123B39,A213,39,34,Maryland,5/13/2012,147157
A123B39,A213,39,34,Maryland,5/13/2012,147157
A123B13,A224,13,,Minnesota,2/18/2012,8751.24
A123B70,A224,70,59,,4/2/2012,8751.24
A123B672,A285AC,672,52,Las Vegas,10/19/2012,7865.73
A123B726,A251ext,726,26,Las Vegas,4/6/2013,4400
A123B21,A214,21,41,Maryland,2/28/2009,1230000000
A123B40,A214,40,35,Austin,6/30/2009,29500  
A123B46,A220,46,32,Austin,12/29/2011,13986 Amount
A123B20,A213,20,42,Redmond,5/18/2013,147157 Price
A123B937,A213,937,35,Minnesota,9/27/2009,147157

以下是将此模式应用于数据集的结果:

  • 有效数据

    A123B39,A213,39,34,Maryland,5/13/2012,147157
    A123B13,A224,13,35,Minnesota,2/18/2012,8751.24
    A123B70,A224,70,59,XXXXX,4/2/2012,8751.24
    A123B937,A213,937,35,Minnesota,9/27/2009,147157
    
  • 无效数据

    A123B672,A285AC,672,52,Las Vegas,10/19/2012,7865.73,Referential check Failed for policy_master_id
    A123B726,A251ext,726,26,Las Vegas,4/6/2013,4400,Referential check Failed for policy_master_id
    A123B21,A214,21,41,Maryland,2/28/2009,1230000000,claim_amount not within range
    A123B40,A214,40,35,Austin,6/30/2009,29500,claim_amount not within range
    A123B46,A220,46,32,Austin,12/29/2011,13986 Amount,InvalidDatatype for claim_amount
    A123B20,A213,20,42,Redmond,5/18/2013,147157 Price,InvalidDatatype for claim_amount
    

获得的 T10 数据可以分为有效数据和无效数据。在之前的结果中,删除了带有claim_id A123B39的重复记录。对于有claim_id A123B13的记录,age的空值被35(中间值)代替,对于有claim_id A123B70的记录,city的空值被XXXXX代替。此外,有效数据还包含与列claim_amountpolicy_master_id上的数据类型、范围和引用完整性约束相匹配的记录列表。无效数据被写入文件夹invalid_data中的文件。文件的最后一列提到了记录被认为无效的原因。

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • Chapter4/code/
  • Chapter4/datasets/

正则表达式验证和清洗设计模式

本设计模式处理使用正则表达式函数验证数据。regex 函数可用于验证数据以匹配特定长度或模式,并清除无效数据。

背景

这个设计模式讨论了如何使用正则表达式函数来识别和清除字段长度无效的数据。该模式还从数据中识别具有指定日期格式的所有值,并删除不符合指定格式的无效值。

动机

识别长度不正确的字符串数据是知道数据是否准确的最快方法之一。通常,我们需要这个字符串长度参数来判断数据,而不需要深入数据。当字符串的长度必须有上限时,这将非常有用,例如,美国州代码的长度上限通常为 2。

查找与日期模式匹配的所有字符串模式是最常见的数据转换之一。日期很容易用多种方式表达(日/月/YY、月/日/YY、年/月/日等)。).转换包括发现这些模式的出现,并将所有这些格式标准化为业务规则所需的统一日期格式。

用例

正则表达式用于要求字符串完全或部分匹配的情况。以下是执行提取、转换和加载 ( ETL )时的一些常见用例:

  • 字符串长度和模式验证:如果数据的结构是标准格式,并且数据匹配指定的长度,则使用正则表达式来验证数据。例如,如果一个字段以字母开头,后跟三个数字,它可以帮助验证数据。
  • 过滤与特定模式不匹配的字段:如果你的业务案例需要你剔除与特定模式不匹配的数据,这个可以在清理阶段使用;例如,筛选日期与预定义格式不匹配的记录。
  • 将字符串拆分成标签:非结构化文本可以使用正则表达式解析并拆分成标签。一个常见的例子是使用\s标记将文本拆分成单词,这意味着按空格拆分。另一个用途是使用模式来分割字符串以获得前缀或后缀。例如,从字符串“100 dollars”中提取100的值。
  • 提取数据匹配模式:这个有一些用处。您可以从一个巨大的文件中提取一些文本匹配模式。文件预处理就是一个例子;您可以形成一个正则表达式,从一个巨大的日志中提取请求或响应模式,并进一步分析提取的数据。

模式实现

该设计模式在 Pig 中作为独立脚本实现。脚本加载数据,并根据正则表达式模式对其进行验证。

  • 字符串模式和长度:脚本验证policy_master_id列中的值是否与预定义的长度和模式匹配。与图案或长度不匹配的值将被删除。
  • 日期格式:脚本验证claim_date列的值是否与 MM/DD/YYYY 日期格式匹配;过滤日期格式无效的记录。

代码片段

为了说明该模型的工作原理,我们考虑一个存储在 HDFS 的汽车保险索赔数据集,它包含两个文件。automobile_policy_master.csv为主文件;它包含唯一的 ID、车辆详细信息、价格和支付的保费。主文件用于验证索赔文件中的数据。automobile_insurance_claims.csv文件包含汽车保险理赔数据,具体为车辆修理费理赔;包括CLAIM_IDPOLICY_MASTER_IDVEHICLE_DETAILSCLAIM_DETAILS等属性。对于这种模式,我们将对POLICY_MASTER_IDCLAIM_DATE进行正则表达式验证和清理,如下代码所示:

/*
Load automobile insurance claims dataset into the relation claims
*/
claims = LOAD'/user/cloudera/pdp/datasets/data_validation/automobile_insurance_claims.csv' USING  PigStorage(',') AS(claim_id:chararray, policy_master_id:chararray,registration_no:chararray, engine_no:chararray,chassis_no:chararray,customer_id:int,age:int,first_name:chararray,last_name:chararray,street:chararray,address:chararray,city:chararray,zip:long,gender:chararray, claim_date:chararray,garage_city:chararray,bill_no:long,claim_amount:chararray,garage_name:chararray,claim_status:chararray);

/*
Validate the values in the column policy_master_id with a regular expression to match the pattern where the value should start with an alphabet followed by three digits.
The values that do not match the pattern or length are considered as invalid values and are removed.
*/
valid_policy_master_id = FILTER claims BY policy_master_id MATCHES'[aA-zZ][0-9]{3}';

/*
Invalid values are stored in the relation invalid_length
*/
invalid_policy_master_id = FILTER claims BY NOT(policy_master_id MATCHES '[aA-zZ][0-9]{3}');
invalid_length = FOREACH invalid_policy_master_id GENERATE $0,$1 ,$2 , $3 ,$4 , $5 ,$6 , $7, $8 ,$9 , $10 , $11, $12, $13 ,$14 , $15 , $16 ,$17 , $18 ,$19,'Invalid length or pattern for policy_master_id' AS reason;

/*
Validate the values in the column claim_date to match MM/DD/YYYY format, also validate the values given for MM and DD to fall within 01 to 12 for month and 01 to 31 for day
The values that do not match the pattern are considered as invalid values and are removed.
*/
valid_claims = FILTER valid_policy_master_id BY( claim_date MATCHES '^(0?[1-9]|1[0-2])[\\/](0?[1-9]|[12][0-9]|3[01])[\\/]\\d{4}$');

/*
Invalid values are stored in the relation invalid_date
*/
invalid_dates = FILTER valid_policy_master_id BY NOT( claim_date MATCHES '^(0?[1-9]|1[0-2])[\\/](0?[1-9]|[12][0-9]|3[01])[\\/]\\d{4}$');
invalid_date = FOREACH invalid_dates GENERATE $0, $1 ,$2 , $3 ,$4 , $5 ,$6 , $7, $8 ,$9 , $10 , $11, $12, $13 , $14 , $15 ,$16 ,$17 , $18 ,$19,'Invalid date format for claim_date' AS reason;

/*
Combine the relations that contain invalid values. 
*/
invalid_claims = UNION invalid_length,invalid_date;

/*
The results are stored on the HDFS in the directories valid_data and invalid_data
The invalid values are written to a file in the folder invalid_data. This file has an additional column specifying the reason for elimination of the record, this can be used for further analysis.
*/
STORE valid_claims INTO'/user/cloudera/pdp/output/data_validation_cleansing/regex_validation_cleansing/valid_data';
STORE invalid_claims INTO'/user/cloudera/pdp/output/data_validation_cleansing/regex_validation_cleansing/invalid_data';

结果

以下为原始数据集的片段;为了提高可读性,我们删除了一些列。

claim_id,policy_master_id,cust_id,age,city,claim_date,claim_amount
A123B1,A290,1,42,Minnesota,1/5/2011,8211
A123B672,A285AC,672,52,Las Vegas,10/19/2012,7865.73
A123B726,A251ext,726,26,Las Vegas,4/6/2013,4400
A123B2,A213,2,35,Redmond,1/22/2009,147157
A123B28,A221,28,19,Austin,6/37/2012,31930.2
A123B888,A247,888,49,Las Vegas,21/20/2012,873
A123B3,A214,3,23,Maryland,7/8/2011,8400

以下是将此模式应用于数据集的结果:

  • 有效数据

    A123B1,A290,1,42,Minnesota,1/5/2011,8211
    A123B2,A213,2,35,Redmond,1/22/2009,147157
    A123B3,A214,3,23,Maryland,7/8/2011,8400
    
  • 无效数据

    A123B672,A285AC,672,52,Las Vegas,10/19/2012,7865.73,Invalid length or pattern for policy_master_id
    A123B726,A251ext,726,26,Las Vegas,4/6/2013,4400,Invalid length or pattern for policy_master_id
    A123B28,A221,28,19,Austin,6/37/2012,31930.2,Invalid date format for claim_date
    A123B888,A247,888,49,Las Vegas,21/20/2012,873,Invalid date format for claim_date
    

如前所示,结果数据分为有效数据和无效数据。有效数据包含符合 regex 模式的记录列表,用于验证policy_master_idclaim_date。无效数据写入invalid_data文件夹中的文件;文件的最后一列提到了记录被认为无效的原因。我们选择过滤无效数据;但是,清理技术取决于业务案例,在这种情况下,无效数据可能必须转换为有效数据。

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • Chapter4/code/
  • Chapter4/datasets/

数据验证和损坏数据清理的设计模式

这个设计模式从被视为噪声或异常值的损坏数据的角度来讨论数据损坏。详细讨论了受损数据的识别和去除技术。

背景

本设计模式探索使用 Pig 来验证和清除数据集中的损坏数据。它试图从传感器到结构化数据的各种大数据源中设置数据损坏的背景。此设计模式从两个角度检测数据损坏,一个是噪声,另一个是异常值,如下表所示:

  • 噪声可以定义为测量中的随机误差,它导致损坏的数据与正确的数据一起被吸收。误差与期望值相差不远。
  • 异常值也是一种噪声,但误差值与期望值相差太远。异常值对分析的准确性有很大影响。它们通常是测量或记录误差。其中一些可以代表有趣的现象,从应用领域的角度来看非常重要,这意味着不应该消除所有的异常值。

受损数据可以表示为噪声或异常值,两者的主要区别在于与期望值的差异程度。噪声数据的变化程度小,其值更接近原始数据,而异常值的变化程度大,其值远离原始数据。为了说明下面这组数字中的例子,4 可以视为噪声,21 可以视为异常值。

A = [1,2,1,4,1,2,1,1,1,2,21,1,2,2]

数据损坏会增加执行分析所需的工作量,还会对数据挖掘分析的准确性产生不利影响。以下几点说明了适用于大数据的几种数据损坏来源:

  • 传感器数据中的数据损坏:传感器数据已经成为我们数据世界大量大数据源中最大的数据源之一。这些传感器通常长时间产生大量数据,由于数据不准确,导致各种计算挑战。Hadoop 被广泛应用于纵向传感器数据中的模式挖掘,而这个过程中最大的挑战之一就是传感器数据的自然误差和不完整性。传感器的电池寿命不足,很多传感器可能长时间无法发送准确的数据,从而损坏数据。
  • 结构化数据中的数据损坏:在结构化大数据的上下文中,任何数据,无论是数字数据还是分类数据,如果存储在 Hadoop 中的方式使其不能被为数据编写的任何数据处理例程读取或使用,都可以被视为损坏。

动机

通过应用适当的噪声和异常检测技术,可以验证和清除损坏的数据。用于此目的的常用技术有宁滨、回归和聚类,如下表所示:

  • 宁滨:这个技术可以用来识别噪声和异常值。该技术也用于通过应用平滑函数来去除噪声数据。宁滨的工作原理是创建一组分类值,这些值被分成不同的容器。这些值除以等频率或等宽度。为了平滑数据(或去除噪声),给定分区或框中的原始数据值被该分区的平均值或中值替换。在当前的设计模式下,我们将解释宁滨消除噪声的适用性。
  • 回归:它是一种将数据值拟合到函数的技术。回归可用于通过识别回归函数并移除远离函数预测值的所有数据值来消除噪声。线性回归找到“最合适”的线性函数来拟合两个变量,这样一个变量可以用来预测另一个变量。线性回归类似于线性回归,涉及两个以上的变量,数据适用于多维曲面。
  • 聚类:离群值分析可以通过聚类来执行,通过将相似的值分组在一起来找到在聚类之外并且可以被认为是离群值的值。一个集群包含的值与同一集群中的其他值相似,但与其他集群中的值不同。您可以将一组值视为一个组,以便在宏级别与其他组值进行比较。

寻找异常值的另一种方法是计算 ( iqr )的四分位数区间。在该方法中,首先根据这些值计算三个四分位数(Q1、Q2 和 Q3)。四分位数将值分成四个相等的组,每个组包含四分之一的数据。上下两列用三个四分位数计算,高于或低于这两列的任何值都被认为是异常值。边界是定义异常值范围的指南。在当前的设计模式中,我们使用这种方法来发现异常值。

用例

您可以考虑使用这种设计模式,通过去除噪声和异常值来去除损坏的数据。这种设计模式将有助于理解如何将数据分类为噪声或异常值,然后将其移除。

模式实现

这个设计模式是使用第三方库datafu.jar作为独立的 Pig 脚本实现的。该脚本实现了识别和去除噪声和异常值。

宁滨技术识别并消除噪音。在宁滨,这些值被分类并分配到多个箱中。确定每个库的最小值和最大值,并将它们设置为库边界。每个箱值由最近的箱边界值代替。这种方法被称为通过面元边界平滑。为了识别异常值,我们使用标准盒图规则方法;它根据数据分布的上四分位数和下四分位数发现异常值。使用 (Q1-C * iqd,Q3+C * iqd) 计算数据分布的 Q1 和 Q3 及其四分位间距,给出数据应该落在的范围。这里,c 是一个值为 1.5 的常数。超出此范围的值被视为异常值。该脚本使用 Datafu 库来计算四分位数。

代码片段

为了说明这个模型的工作原理,我们考虑一个存储在 HDFS 的汽车保险理赔数据集,它包含两个文件。automobile_policy_master.csv为主文件;它包含唯一的 ID、车辆详细信息、价格和支付的保费。主文件用于验证索赔文件中的数据。automobile_insurance_claims.csv文件包含汽车保险理赔数据,具体为车辆修理费理赔;包括CLAIM_IDPOLICY_MASTER_IDVEHICLE_DETAILSCLAIM_DETAILS等属性。对于该模式,我们将在CLAIM_AMOUNTAGE上验证和清理损坏的数据,如下代码所示:

/*
Register Datafu jar file
*/
REGISTER  '/home/cloudera/pdp/jars/datafu.jar';

/*
Define alias for the UDF quantile
The parameters specify list of quantiles to compute
*/
DEFINE Quantile datafu.pig.stats.Quantile('0.25','0.50','0.75'); 

/*
Load automobile insurance claims data set into the relation claims
*/
claims = LOAD'/user/cloudera/pdp/datasets/data_validation/automobile_insurance_claims.csv' USING  PigStorage(',') AS(claim_id:chararray, policy_master_id:chararray,registration_no:chararray, engine_no:chararray,chassis_no:chararray,customer_id:int,age:int,first_name:chararray,last_name:chararray,street:chararray,address:chararray,city:chararray,zip:long,gender:chararray, claim_date:chararray,garage_city:chararray,bill_no:long,claim_amount:double,garage_name:chararray,claim_status:chararray);

/*
Sort the relation claims by age
*/
claims_age_sorted = ORDER claims BY age ASC;

/*
Divide the data into equal frequency bins. 
Minimum and maximum values are identified for each bin and are set as bin boundaries.
Replace each bin value with the nearest bin boundary.
*/
bin_id_claims = FOREACH claims_age_sorted GENERATE(customer_id - 1) * 10 / (130- 1 + 1) AS bin_id, $0 ,$1 ,$2 ,$3 ,$4 ,$5 ,$6 ,$7 ,$8 ,$9 ,$10 ,$11 ,$12 ,$13 ,$14 ,$15 ,$16 ,$17 ,$18 ,$19 ;
group_by_id = GROUP bin_id_claims BY bin_id;
claims_bin_boundaries = FOREACH group_by_id
{
  bin_lower_bound=(int) MIN(bin_id_claims.age);
  bin_upper_bound = (int)MAX(bin_id_claims.age);
  GENERATE bin_lower_bound AS bin_lower_bound, bin_upper_bound ASbin_upper_bound, FLATTEN(bin_id_claims);
};
smoothing_by_bin_boundaries = FOREACH claims_bin_boundariesGENERATE $3 AS claim_id,$4 AS policy_master_id,$5 ASregistration_no,$6 AS engine_no,$7 AS chassis_no,$8 AS customer_id,( ( $9 - bin_lower_bound ) <=( bin_upper_bound - $9 ) ? bin_lower_bound : bin_upper_bound )AS age,$10 AS first_name,$11 AS last_name,$12 AS street,$13 AS address,$14 AS city,$15 AS zip,$16 AS gender,$17 AS claim_date,$18 AS garage_city,$19 AS bill_no,$20 AS claim_amount,$21 AS garage_name,$22 AS claim_status;

/*
Identify outliers present in the column claim_amount by calculating the quartiles, interquartile distance and the upper and lower fences.
The values that do not fall within this range are considered as outliers and are filtered out.
*/
groupd = GROUP smoothing_by_bin_boundaries ALL;
quantiles = FOREACH groupd { 
  sorted = ORDER smoothing_by_bin_boundaries BY claim_amount;
  GENERATE Quantile(sorted.claim_amount) AS quant;
}
valid_range = FOREACH quantiles GENERATE(quant.quantile_0_25 - 1.5 * (quant.quantile_0_75 - quant.quantile_0_25)) ,(quant.quantile_0_75 + 1.5 *(quant.quantile_0_75 - quant.quantile_0_25));
claims_filtered_outliers = FILTER smoothing_by_bin_boundaries BYclaim_amount>= valid_range.$0 AND claim_amount<= valid_range.$1;

/*
Store the invalid values in the relation invalid_claims
*/
invalid_claims_filter = FILTER smoothing_by_bin_boundaries BY claim_amount<= valid_range.$0 OR claim_amount>= valid_range.$1;
invalid_claims = FOREACH invalid_claims_filter GENERATE $0 ,$1 ,$2 ,$3 ,$4 ,$5 ,$6 ,$7 ,$8 ,$9 ,$10 ,$11 ,$12 ,$13 ,$14 ,$15 ,$16 ,$17 ,$18 ,$19,'claim_amount identified as Outlier' as reason;

/*
The results are stored on the HDFS in the directories valid_data and invalid_data
The invalid values are written to a file in the folder invalid_data. This file has an additional column specifying the reason for elimination of the record, this can be used for further analysis.
*/
STORE invalid_claims INTO'/user/cloudera/pdp/output/data_validation_cleansing/corrupt_data_validation_cleansing/invalid_data';
STORE claims_filtered_outliers INTO'/user/cloudera/pdp/output/data_validation_cleansing/corrupt_data_validation_cleansing/valid_data';

结果

以下为原始数据集的片段;为了提高可读性,我们删除了一些列。

claim_id,policy_master_id,cust_id,age,city,claim_date,claim_amount
A123B6,A217,6,42,Las Vegas,6/25/2010,-12495
A123B11,A222,11,21,,11/5/2012,293278.7,claim_amount identified asOutlier
A123B2,A213,2,42,Redmond,1/22/2009,147157,claim_amount identifiedas Outlier
A123B9,A220,9,21,Maryland,9/20/2011,13986
A123B4,A215,4,42,Austin,12/16/2011,35478

以下是将此模式应用于数据集的结果:

  • 有效数据

    A123B6,A217,6,42,Las Vegas,6/25/2010,-12495
    A123B9,A220,9,21,Maryland,9/20/2011,13986
    A123B4,A215,4,42,Austin,12/16/2011,35478
    
  • 无效数据

    A123B11,A222,11,21,,11/5/2012,293278.7,claim_amount identified as Outlier
    A123B2,A213,2,42,Redmond,1/22/2009,147157,claim_amount identified as Outlier
    

如前所示,结果数据分为有效数据和无效数据。有效数据有一个记录列表,其中age列的噪声被平滑。检测claim_amount栏的异常值,上下栏标为-34929.070935.0;不在此范围内的值被识别为异常值,并写入文件夹invalid_data中的文件。文件的最后一列显示了记录被认为无效的原因。过滤异常值,数据存储在valid_data文件夹中。删除离群值的前一个脚本;但是,这一决定可能会因业务规则而异。

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • Chapter4/code/
  • Chapter4/datasets/

非结构化文本数据验证和清理的设计模式

非结构化文本验证和清理模式 n 演示了应用各种数据预处理技术清理非结构化数据的方法。

背景

用 Hadoop 处理海量非结构化数据是一项具有挑战性的任务,需要清理并做好处理准备。文本数据,包括文档、电子邮件、文本文件和聊天文件,在被 Hadoop 接收时,本质上是无组织的,没有定义的数据模型。

为了打开非结构化数据进行分析,我们必须引入类似于结构的东西。组织非结构化数据的基础是通过在数据存储中执行有计划和有控制的数据清理转换和流动,将其与企业中现有的结构化数据集成在一起进行操作和/或分析。非结构化数据的集成对于结果数据的有意义的查询和分析是必要的。

接收非结构化数据后的第一步是从文本数据中发现元数据,并以有利于进一步处理的方式进行组织,从而消除数据中的一些不规则和歧义。这种元数据的创建本身就是一个多步骤的迭代过程,采用各种数据解析、清洗和转换技术,从简单的实体提取和语义标注到使用人工智能算法的自然语言处理。

动机

该设计模式展示了一种通过执行预处理步骤来清理非结构化数据语料库的方法,如小写转换、停止词移除、词干、标点符号移除、额外空间移除、数字识别和拼写错误识别。

这个模型的动机是了解非结构化数据中的各种不一致性,并帮助识别和消除这些问题。

非结构化数据容易出现从完整性到不一致性的各种质量问题。以下是非结构化文本的常见清理步骤:

  • 文本也可以用替代拼写来表示;例如,一个名字可以用不同的方式书写。如果拼写不同,但仍然指向同一个实体,则搜索该名称将不会得到结果。一方面,可以认为是拼写错误。集成和清理这些替代拼写来引用同一个实体可以减少歧义。从非结构化文本到结构化格式的有效转换需要我们考虑所有可选的拼写。
  • 拼写错误也是很多不规范的原因,会影响分析的准确性。为了使数据可处理,我们必须识别拼错的单词并用正确的单词替换它们。
  • 文本中的数字标识使我们能够选择所有的数字。根据业务环境,这些提取的号码可以包含在进一步的处理中或从进一步的处理中删除。数据清理也可以通过从文本中提取数字来执行;例如,如果文本由短语“1000”组成,则可以将其转换为 1000 来执行适当的分析。
  • 使用正则表达式提取与特定模式匹配的数据可能是一种清理方法。例如,您可以通过指定模式从文本中提取日期。如果提取的日期不是标准格式(DD/MM/YY),则标准化日期可能是按日期读取和索引非结构化数据的清理活动之一。

用例

考虑数据被 Hadoop 摄取后,这种设计模式可以通过删除拼写错误、标点符号等来清理非结构化数据。

模式实现

这个设计模式实现为一个独立的 Pig 脚本,内部使用右连接去除停止词。Stopword 列表首先从外部文本文件加载到关系中,然后在外部连接中使用。

LOWER功能用于将所有单词转换为小写。使用REPLACE功能匹配特定单词删除标点符号。同样,通过使用REPLACE匹配文本中所有数字的模式来删除数字。

拼错单词的代码使用布鲁姆过滤器,该过滤器最近在 0.10 版本中被包含为 UDF。

Bloom filter 是一种空间优化的数据结构,专门用于通过测试属于较小数据集的元素是否是较大数据集的成员,从较大的数据集中过滤出较小的数据集。Bloom filter 内部实现了一种巧妙的机制来存储每个元素,从而使用恒定的内存量,而不管元素的大小,从而实现彻底的空间优化。虽然布隆过滤器与其他结构相比具有巨大的空间优势,但过滤并不完全准确,因为可能存在误报的可能性。

Pig 通过调用BuildBloom来支持 Bloom filter,通过从 Pig 关系中存储的字典语料库加载的值列表中加载和训练 Bloom filter 来构建 Bloom filter。存储在分布式缓存中并内部传输到Mapper功能的经过训练的布隆过滤器用于通过使用BLOOM UDF 进行FILTER操作来对输入数据执行实际的过滤操作。在布隆过滤器消除所有拼写错误的单词后,过滤后的结果集将是拼写正确的单词。

代码片段

为了演示这个模型是如何工作的,我们考虑了存储在 HDFS 可访问的文件夹中的维基百科文本语料库。这个样本语料库由与计算机科学和信息技术相关的维基页面组成。一些拼错的单词被故意引入语料库,以展示该模型的功能。

/*
Define alias for the UDF BuildBloom.
The first parameter to BuildBloom constructor is the hashing technique to use, the second parameter specifies the number of distinct elements that would be placed in the filter and the third parameter is the acceptable rate of false positives.
*/
DEFINE BuildBloom BuildBloom('jenkins', '75000', '0.1');

/*
Load dictionary words
*/
dict_words1 = LOAD'/user/cloudera/pdp/datasets/data_validation/unstructured_text/dictionary_words1.csv' as (words:chararray); 
dict_words2 = LOAD'/user/cloudera/pdp/datasets/data_validation/unstructured_text/dictionary_words2.csv' as (words:chararray);

/*
Load stop words
*/
stop_words_list = LOAD'/user/cloudera/pdp/datasets/data_validation/unstructured_text/stopwords.txt' USING PigStorage();
stopwords = FOREACH stop_words_list GENERATEFLATTEN(TOKENIZE($0));

/*
Load the document corpus and tokenize to extract the words
*/
doc1 = LOAD'/user/cloudera/pdp/datasets/data_validation/unstructured_text/computer_science.txt' AS (words:chararray);
docWords1 = FOREACH doc1 GENERATE FLATTEN(TOKENIZE(words)) ASword;
doc2 = LOAD'/user/cloudera/pdp/datasets/data_validation/unstructured_text/information_technology.txt' AS (words:chararray);
docWords2 = FOREACH doc2 GENERATE FLATTEN(TOKENIZE(words)) ASword;

/*
Combine the contents of the relations docWords1 and docWords2
*/
combined_docs = UNION docWords1, docWords2;

/*
Convert to lowercase, remove stopwords, punctuations, spaces, numbers.
Replace nulls with the value "dummy string"
*/
lowercase_data = FOREACH combined_docs GENERATEFLATTEN(TOKENIZE(LOWER($0))) as word;
joind = JOIN stopwords BY $0 RIGHT OUTER, lowercase_data BY $0;
stop_words_removed = FILTER joind BY $0 IS NULL;
punctuation_removed = FOREACH stop_words_removed  
{
  replace_punct = REPLACE($1,'[\\p{Punct}]','');
  replace_space = REPLACE(replace_punct,'[\\s]','');
  replace_numbers = REPLACE(replace_space,'[\\d]','');
  GENERATE replace_numbers AS replaced_words;
}
replaced_nulls = FOREACH punctuation_removed GENERATE(SIZE($0) > 0 ? $0 : 'dummy string') as word;

/*
Remove duplicate words
*/
unique_words_corpus = DISTINCT replaced_nulls;

/*
Combine the two relations containing dictionary words
*/
dict_words = UNION dict_words1, dict_words2;

/*
BuildBloom builds a bloom filter that will be used in Bloom.
Bloom filter is built on the relation dict_words which contains all the dictionary words.
The resulting file dict_words_bloom is used in bloom filter by passing it to Bloom.
The call to bloom returns the words that are present in the dictionary, we select the words that are not present in the dictionary and classify them as misspelt words. The misspelt words are filtered from the original dataset and are stored in the folder invalid_data.
*/
dict_words_grpd = GROUP dict_words all;
dict_words_bloom = FOREACH dict_words_grpd GENERATEBuildBloom(dict_words.words);
STORE dict_words_bloom into 'dict_words_bloom';
DEFINE bloom Bloom('dict_words_bloom');
filterd = FILTER unique_words_corpus BY NOT(bloom($0));
joind = join filterd by $0, unique_words_corpus by $0;
joind_right = join filterd by $0 RIGHT, unique_words_corpus BY $0;
valid_words_filter = FILTER joind_right BY $0 IS NULL;
valid_words = FOREACH valid_words_filter GENERATE $1;
misspellings = FOREACH joind GENERATE $0 AS misspelt_word;

/*
The results are stored on the HDFS in the directories valid_data and invalid_data.
The misspelt words are written to a file in the folder invalid_data.
*/
STORE misspellings INTO'/user/cloudera/pdp/output/data_validation_cleansing/unstructured_data_validation_cleansing/invalid_data';
STORE valid_words INTO'/user/cloudera/pdp/output/data_validation_cleansing/unstructured_data_validation_cleansing/valid_data';

结果

以下单词被识别为拼写错误,并存储在文件夹invalid_data中。我们选择从原始数据集中过滤这些单词。但是,这取决于业务规则;如果业务规则要求拼错的单词必须用正确的拼写替换,则必须采取适当的步骤来纠正拼写。

sme
lemme
puttin
speling
wntedly
mistaces
servicesa
insertingg
missspellingss
telecommunications

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • Chapter4/code/
  • Chapter4/datasets/

总结

在本章中,您学习了各种大数据验证和清理技术,这些技术用于检测和清理数据中不正确或不准确的记录。这些技术保证了不一致的数据在用于分析过程之前,可以通过按照一套规则对数据进行验证来识别,然后根据业务规则对不一致的数据进行替换、修改或删除,使其更加一致。在本章中,我们学习了上一章中关于数据分析的知识。

在下一章中,我们将重点介绍数据转换模式,它可以应用于多种数据格式。阅读本章后,读者将能够使用聚合、归纳和连接等技术选择正确的模式来转换数据。

五、数据转换模式

在上一章中,您了解了与数据验证和清理相关的各种模式,从中您了解到有许多方法可以检测和删除数据中不正确或不准确的记录。当数据验证和清理完成时,甚至在数据被用于分析生命周期的下一步之前,数据中的不一致性就被识别出来了。然后,替换、修改或删除不一致的数据,使其更加一致。

在本章中,您将了解与数据转换相关的各种设计模式,例如结构化到分层、标准化、集成、聚合和一般化的设计模式。

数据转换过程

数据转换的过程是大数据分析知识发现过程的基本组成部分之一,也是至关重要的一步。数据转换是一个迭代的过程,将源数据修改成一种格式,使分析算法得到有效应用。通过确保以有利于应用分析的格式存储和检索数据,转换提高了算法的性能和准确性。这是通过提高源数据的整体质量来实现的。

大数据的数据转换主要包括以下主要过程:

  • 归一化:本次变换对属性数据进行缩放,使其在指定范围内。通常,属性值被转换为适合 0 到 1 之间的范围。这是为了消除某些属性对分析的一些不必要的影响。规范化转换不同于关系数据库设计中使用的第一、第二和第三范式。
  • 聚合:这个转换执行数据聚合操作,比如从每日的股票数据计算出月度和年度汇总,从而创建一个多维度和粒度分析的数据立方体。
  • 泛化:在的变换中,使用概念层次将低级原始数据替换为更高级的抽象。例如,根据分析用例,低层数据(如街道)可以被高层抽象(如城市或州)所替代。
  • 数据集成:是将多个结构相似或不相似的输入管道的数据连接成单个输出管道的过程。

以下部分详细描述了最常用的 Pig 设计模式,这些模式有助于数据转换。

从结构化到分层的转换模式

结构到层次的转换模式通过从结构化数据生成层次结构(如 XML 或 JSON)来处理数据转换。

背景

从结构到层次的转换模式创建了一个新的层次结构,比如 JSON 或 XML,数据存储在一个扁平的类似行的结构中。这是一种创建新记录的数据转换模式。与原始记录相比,新记录以不同的结构表示。

动机

Hadoop 擅长整合多个来源的数据,但要及时进行分析连接,始终是一项复杂耗时的操作。

为了高效地执行某些类型的分析(如日志文件分析),数据有时不需要以标准化的形式存储在 Hadoop 中。将标准化数据存储在多个表中会产生一个额外的步骤,将所有数据连接在一起以对它们进行分析—连接通常在标准化结构化数据上执行,以将来自多个源的数据与外键关系集成在一起。

相反,原始数据通过反规格化分层嵌套。这种数据预处理将确保高效分析。

NoSQL 数据库,如 HBase、Cassandra 或 MongoDB,有助于将平面数据存储在列族或 JSON 对象中。Hadoop 可用于以批处理模式集成来自多个来源的数据,并创建可轻松插入这些数据库的分层数据结构。

用例

这种设计模式主要适用于集成来自多个独立数据源的结构化和基于行的数据。这种集成的具体目标是将数据转换成层次结构,以便可以分析数据。

这种模式对于将单个源中的数据转换成层次结构,然后使用层次结构将数据加载到柱状数据库和 JSON 数据库中也很有用。

模式实现

Pig 对元组和包形式的分层数据有现成的支持,用于在一行中表示嵌套对象。COGROUP运算符将数据分组为一个或多个关系,并创建输出元组的嵌套表示。

这种设计模式在 Pig 中作为独立的脚本实现。该脚本通过从结构化格式生成数据的分层表示来演示这种模式的用法。这个脚本加载一个非规范化的 CSV 文件,并将其传递给一个自定义的 Java UDF。Java UDF 使用XMLParser来构建一个 XML 文件。自定义存储函数以 XML 格式存储结果。

代码片段

为了说明该模型的工作原理,我们考虑存储在 HDFS 的制造数据集。文件production_all.csv包含从production.csvmanufacturing_units.csv导出的反规格化数据。我们将把结构化数据从 CSV 格式转换成层次化的 XML 格式。

PIG 脚本从结构化到分层的设计模式如下:

/*
Register the piggybank jar and generateStoreXml jar, it is a custom storage function which generates an XML representation and stores it
*/
REGISTER '/home/cloudera/pdp/jars/generateStoreXml.jar';
REGISTER '/usr/share/pig/contrib/piggybank/java/piggybank.jar';

/*
Load the production dataset into the relation production_details
*/
production_details = LOAD'/user/cloudera/pdp/datasets/data_transformation/production_all.csv' USING  PigStorage(',') AS(production_date,production_hours,manufacturing_unit_id,manufacturing_unit_name,currency,product_id,product_name,quantity_produced);

/*
Call the custom store function TransformStoreXML to transform the contents into a hierarchical representation i.e XML and to store it in the directory structured_to_hierarchical
*/
STORE production_details INTO'/user/cloudera/pdp/output/data_transformation/structured_to_hierarchical' USINGcom.xmlgenerator.TransformStoreXML('production_details','production_data');

以下是之前的 Pig 脚本用来执行结构到层次转换的 Java UDF 的片段:

  /**
   * data from tuple is appended to xml root element
   * @param tuple
   */
  protected void write(Tuple tuple)
  {
    // Retrieving all fields from the schema
    ResourceFieldSchema[] fields = schema.getFields();
    //Retrieve values from tuple
    List<Object> values = tuple.getAll();
    /*Creating xml element by using fields as element tag 
and tuple value as element value*/
    Element transactionElement =xmlDoc.createElement(TransformStoreXML.elementName);
    for(int counter=0;counter<fields.length;counter++)
    {
      //Retrieving element value from values
      String columnValue = String.valueOf(values.get(counter));
      //Creating element tag from fields
      Element columnName = xmlDoc.createElement(fields[counter].getName().toString().trim());
      //Appending value to element tag

      columnName.appendChild(xmlDoc.createTextNode(columnValue));
      //Appending element to transaction element
        transactionElement.appendChild(columnName);    
    }
    //Appending transaction element to root element
    rootElement.appendChild(transactionElement);
  }

结果

以下是对输入执行代码后生成的 XML 文件的片段:

<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<production_details>
  <production_data>
    <production_date>2011-01-01T00:00:00</production_date>
    <production_hours>7</production_hours>
    <manufacturing_unit_id>1</manufacturing_unit_id>
    <manufacturing_unit_name>unit1</manufacturing_unit_name>
    <currency>USD</currency>
    <product_id>C001</product_id>
    <product_name>Refrigerator 180L</product_name>
    <quantity_produced>49</quantity_produced>
  </production_data>
  <production_data>
    .
    .
    .

  </production_data>
  .
  .
  .
</production_details>

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • Chapter5/code/
  • Chapter5/datasets/

数据归一化模式

数据标准化设计模式讨论了数据值标准化或规范化的方法。

背景

数据标准化是指将在不同尺度上测量的数据值拟合、调整或缩放到概念上的共同范围。举一个简单的例子,将数据集与不同的距离测量单位(如公里和英里)连接起来,当它们不标准化时,可以提供不同的结果。因此,它们被标准化,使它们返回到一个共同的单位,如公里或英里,这样不同测量单位的影响就不会被分析所感觉到。

动机

大数据中集成多个数据源时,在同一个数据属性中遇到不同的值是很常见的。

数据预处理和转换是通过标准化原始数据并将其缩放到指定范围(例如,0 到 1 的范围)以及为所有属性分配相等的权重来执行的。在标准化数据之前,从数据中移除任何异常值。当分析可能受到较高范围内测量单位和值的选择的影响时,需要数据标准化。

规范化用于分析,如聚类,这是一种基于距离的方法,可防止值较高的属性支配值较小的属性。标准化数字和非数字数据的技术如下:

  • Normalizing numeric data: Numeric data is normalized using methods such as min-max normalization, thus transforming the data to a value between a specified range [newMin, newMax]. The minValue and maxValue are usually identified from the dataset and the normalization is done by applying the following formula for each value:

    Normalized value = [(value-minimum)/(maximum-minimum)) * (new maximum-new minimum)+new minimum]

  • 归一化非数值数据:非数值数据首先转换为数值数据,然后归一化。例如,如果评级属性的值可以是优秀、非常好、良好、一般、低于一般、差或最差,则可以将其转换为 1 到 7 之间的数值;因此,这些值可以被归一化以适合模型。

用例

可以考虑用这个设计模式作为预处理技术进行分析。这种模式可以用于用例分析,以避免初始值较高的属性和初始值较低的属性之间的对比。

这种模式可以被视为封装原始数据的一种方法,因为它通过规范化来转换原始数据。

模式实现

这个设计模式在 Pig 中作为独立脚本实现。用例识别给定产品的相似制造单元;它显示了标准化。该脚本为产品C001的每个制造单元加载数据并计算total produced quantitytotal production hours。每个制造单元由producttotal produced quantitytotal production hours表示。该脚本使用最小-最大归一化技术归一化total number of units producedtotal production hours,以便将所有值设置为相同的比率(范围从 0 到 1)。然后,脚本计算这些点之间的欧几里德距离。距离越小,制造单位越相似。

代码片段

为了说明该模型的工作原理,我们考虑存储在 HDFS 的制造数据集。文件production.csv包含各制造单元的生产信息;该文件包含production_dateproduction_hoursmanufacturing_unit_idproduct_idproduced_quantity等属性。我们将为产品C001的每个制造单元计算total produced quantitytotal production hours,如下代码所示:

/*
Load the production dataset into the relation production
*/
production = LOAD'/user/cloudera/pdp/datasets/data_transformation/production.csv' USING PigStorage(',') AS(production_date:datetime,production_hours:int,manufacturing_unit_id:chararray,product_id:chararray,produced_quantity:int);

/*
Filter the relation products to fetch the records with product id C001
*/
production_filt = FILTER production BY product_id=='C001';

/*
Calculate the total production hours and total produced quantity of product C001 in each manufacturing unit
*/
production_grpd = GROUP production_filt BY(manufacturing_unit_id,product_id);
production_sum = FOREACH production_grpd GENERATE group.$0 ASmanufacturing_unit_id, group.$1 AS product_id,(float)SUM(production_filt.production_hours) ASproduction_hours,(float)SUM(production_filt.produced_quantity)AS produced_quantity;

/*
Apply Min max normalization on total production hours and total produced quantity for each manufacturing unit to scale the data to fit in the range of [0-1]
*/
production_sum_grpd = GROUP production_sum ALL;
production_min_max = FOREACH production_sum_grpd GENERATEMIN(production_sum.production_hours)-1 ASmin_hour,MAX(production_sum.production_hours)+1 AS max_hour,MIN(production_sum.produced_quantity)-1 AS min_qty,MAX(production_sum.produced_quantity)+1 AS max_qty;
production_norm = FOREACH production_sum 
{
  norm_production_hours = (float)(((production_hours -production_min_max.min_hour)/(production_min_max.max_hour -production_min_max.min_hour))*(1-0))+1;
  norm_produced_quantity = (float)(((produced_quantity -production_min_max.min_qty)/(production_min_max.max_qty -production_min_max.min_qty))*(1-0))+1;
  GENERATE manufacturing_unit_id AS manufacturing_unit_id,product_id AS product_id, norm_production_hours ASproduction_hours, norm_produced_quantity AS produced_quantity;
}
prod_norm = FOREACH production_norm GENERATE manufacturing_unit_idAS manufacturing_unit_id,product_id ASproduct_id,production_hours ASproduction_hours,produced_quantity AS produced_quantity;

/*
Calculate the Euclidean distance to find out similar manufacturing units w.r.t the product C001
*/
manufacturing_units_euclidean_distance  = FOREACH (CROSS production_norm,prod_norm) {
distance_between_points = (production_norm::production_hours -prod_norm::production_hours)*(production_norm::production_hours -prod_norm::production_hours) +(production_norm::produced_quantity -prod_norm::produced_quantity)*(production_norm::produced_quantity - prod_norm::produced_quantity);
GENERATE  production_norm::manufacturing_unit_id,production_norm::product_id,prod_norm::manufacturing_unit_id,prod_norm::product_id,SQRT(distance_between_points) as dist;         
};

/*
The results are stored on the HDFS in the directory data_normalization
*/
STORE manufacturing_units_euclidean_distance INTO'/user/cloudera/pdp/output/data_transformation/data_normalization';

结果

以下是对输入执行代码后生成的结果片段:

1  C001  1  C001  0.0
1  C001  3  C001  1.413113776343348
1  C001  5  C001  0.2871426024640011
3  C001  1  C001  1.413113776343348
3  C001  3  C001  0.0
3  C001  5  C001  1.1536163027782005
5  C001  1  C001  0.2871426024640011
5  C001  3  C001  1.1536163027782005
5  C001  5  C001  0.0

制造单位之间的相似度是为一个产品(C001)计算的。如前所示,制造单元15与产品C001相似,因为它们之间的距离小于其他单元之间的距离。

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • Chapter5/code/
  • Chapter5/datasets/

数据整合模式

数据集成模式处理的是多来源数据集成的方法,以及解决此活动产生的数据不一致的技术。

背景

这个模型讨论了整合多个来源的数据的方法。数据集成有时会导致数据不一致。例如,不同的数据源可能使用不同的测量单位。解决数据不一致的集成模式处理技术。

动机

对于许多大数据解决方案来说,数据存在于不同的地方是很常见的,例如 SQL 表、日志文件和 HDFS。为了发现不同地方的数据之间令人兴奋的关系,有必要从不同的来源获取和整合这些数据。另一方面,这种来自多个来源的数据集成有时会导致数据不一致。的数据集成通过添加更多的属性并赋予它更多的意义和上下文来丰富它。它还可以通过删除不必要的细节来过滤数据。

数据集成主要通过连接操作来实现。联接操作基于名为外键的字段集成多个数据集中的记录。外键是表中等于另一个表的列的字段。它被用作表间交叉引用的手段。虽然这个操作在 SQL 中相当简单,但是 MapReduce 的工作方式使它成为 Hadoop 上最昂贵的操作之一。

以下示例以两个数据集 A 和 B 为例,说明了理解不同类型联接的简单方法。下图显示了每个数据集中的值。

Motivation

以下是可以在数据集上执行的不同类型的连接:

  • Inner join: When this is performed on two datasets, all the matching records from both the datasets are returned. As shown in the following figure, it returns the matching records (2, 3) from both the datasets.

    Motivation

  • Left outer join: When this is performed on two datasets, all the matching records from both the datasets are returned along with the unmatched records from the dataset on the left-hand side. As shown in the following figure, the matched records (2, 3) along with the unmatched record in the dataset to the left (1) are returned.

    Motivation

  • Right outer join: When this is performed on two datasets, all the matching records from both the tables are returned along with the unmatched records from the dataset on the right-hand side. As shown in the following figure, the matched records (2, 3) along with the unmatched record in the dataset to the right (4) are returned.

    Motivation

  • Full outer join: When this is applied on two datasets, all the matching records from both the tables are returned along with the unmatched records from both tables. As shown in the following figure, the matched records (2, 3) along with unmatched records in both the datasets (1, 4) are returned.

    Motivation

  • Cartesian join: When the Cartesian join is performed on two datasets, each record from the first dataset and all the records of the second dataset are joined together. As shown in the following figure, the result would be (1, 2), (1, 3), (1, 4), (2, 2), (2, 3), (2, 4), (3, 2), (3, 3), and (3, 4).

    Motivation

组合来自多个来源的数据可能会导致数据不一致。不同的数据源可能使用不同的度量单位。例如,假设有两个数据源,并且每个数据源使用不同的货币,例如美元对欧元。因此,这两个来源整合的数据是不一致的。另一个问题是,每个源中的数据可能以不同的方式表示,例如真/假是/否。您必须使用数据转换来解决这些不一致。

在清管器中执行连接操作有两种主要技术:

  • 递减末端连接: 【T2】第一种技术在 MapReduce 术语中称为递减末端连接。它在几个具有外键关系的大型数据集上使用默认连接运算符。该技术执行任何类型的连接操作(内部、外部、右侧、左侧等)。)对数据集的影响。此外,它可以同时处理多个数据集。这种连接操作最大的缺点就是会给网络带来巨大的负载,因为所有被连接的数据都是先进行排序,然后再发送给减速器,这就减缓了这种操作的执行速度。
  • 复制连接: 第二种技术叫复制连接,使用replicated关键字和Join运算符语法。这种连接技术适用于非常大的数据集和许多小数据集。在内部,这种连接只在映射器端执行,不需要额外的数据排序和洗牌。复制允许 Pig 向每个节点分发一个小数据集(小到足以容纳内存),这样数据集就可以直接连接到地图作业,从而消除了减少作业的需要。复制中并不支持所有类型的连接;它只支持内部连接和左侧外部连接。

用例

您可以考虑在以下场景中使用这种设计模式:

  • 当您需要在应用分析之前组合来自多个来源的数据时
  • 通过反规格化数据减少处理时间;去规范化可以通过将事务数据集与其关联的主数据集连接来实现。
  • 转换数据,解决数据集成带来的数据不一致。
  • 使用特定连接过滤数据。

模式实现

这个设计模式在 Pig 中作为独立脚本实现。它结合了所有制造单元的生产信息,通过转换数据来解决数据不一致的问题,并找出每个单元是否发挥了最佳性能。

该脚本首先加载每个制造单元的数据,并使用UNION进行组合。然后,它通过将连接应用于生产数据集及其主数据集来反规格化数据,以获得manufacturing unitproduct details。它实现了复制连接,将一个巨大的生产数据集与一个更小的名为 products 的数据集连接起来。一个单位使用印度卢比作为其货币;这导致数据不一致。该脚本通过将单位的制造成本属性(以印度卢比表示)转换为美元来解决这种不一致。

然后,脚本将每个单元的the actual quantity producedexpected quantity进行比较,以确定每个单元是否具有最佳性能。

代码片段

为了说明该模型的工作原理,我们考虑存储在 HDFS 的制造数据集。它包含三个主要文件;manufacturing_units.csv包含每个制造单元的信息,products.csv包含制造产品的详细信息,manufacturing_units_products.csv存储不同制造单元制造的产品的详细信息。生产数据集对于每个制造单元都有一个单独的生产文件;该文件包含 T3、T4、T5、T6 和 T7 等属性。下面的代码是 Pig 脚本,它演示了这种模式的实现:

/*
Load the production datasets of five manufacturing units into the relations
*/
production_unit_1 = LOAD'/user/cloudera/pdp/datasets/data_transformation/production_unit_1.csv' USING PigStorage(',') AS(production_date:datetime,production_hours:int,manufacturing_unit_id:chararray,product_id:chararray,produced_quantity:int);
production_unit_2 = LOAD'/user/cloudera/pdp/datasets/data_transformation/production_unit_2.csv' USING PigStorage(',') AS(production_date:datetime,production_hours:int,manufacturing_unit_id:chararray,product_id:chararray,produced_quantity:int);
production_unit_3 = LOAD'/user/cloudera/pdp/datasets/data_transformation/production_unit_3.csv' USING PigStorage(',') AS(production_date:datetime,production_hours:int,manufacturing_unit_id:chararray,product_id:chararray,produced_quantity:int);
production_unit_4 = LOAD'/user/cloudera/pdp/datasets/data_transformation/production_unit_4.csv' USING PigStorage(',') AS(production_date:datetime,production_hours:int,manufacturing_unit_id:chararray,product_id:chararray,produced_quantity:int);
production_unit_5 = LOAD'/user/cloudera/pdp/datasets/data_transformation/production_unit_5.csv' USING PigStorage(',') AS(production_date:datetime,production_hours:int,manufacturing_unit_id:chararray,product_id:chararray,produced_quantity:int);

/*
Combine the data in the relations using UNION operator
*/
production = UNIONproduction_unit_1,production_unit_2,production_unit_3,production_unit_4,production_unit_5;

/*
Load manufacturing_unit and manufacturing_units_products datasets
*/
manufacturing_units_products = LOAD'/user/cloudera/pdp/datasets/data_transformation/manufacturing_units_products.csv' USING PigStorage(',') AS(manufacturing_unit_id:chararray,product_id:chararray,capacity_per_hour:int,manufacturing_cost:float);
manufacturing_units = LOAD'/user/cloudera/pdp/datasets/data_transformation/manufacturing_units.csv' USING PigStorage(',') AS(manufacturing_unit_id:chararray,manufacturing_unit_name:chararray,manufacturing_unit_city:chararray,country:chararray,currency:chararray);

/*
Use replicated join to join the relation production, which is huge with a smaller relation manufacturing_units_products.
The relations manufacturing_units_products and manufacturing units are small enough to fit into the memory
*/
replicated_join = JOIN production BY(manufacturing_unit_id,product_id),manufacturing_units_products BY(manufacturing_unit_id,product_id) USING 'replicated';
manufacturing_join = JOIN replicated_join BYproduction::manufacturing_unit_id, manufacturing_units BYmanufacturing_unit_id USING 'replicated';

/*
Identify varying representation of currency and transform the values in the attribute manufacturing_cost to USD for the units that have INR as currency
*/
transformed_varying_values = FOREACH manufacturing_join GENERATE$0 AS production_date,$2 AS manufacturing_unit_id,$3 ASproduct_id,$4 AS actual_quantity_produced,($1*$7) AS expected_quantity_produced,(float)((($13 == 'INR') ?($8/60) : $8)*$4) AS manufacturing_cost;

/*
Calculate the expected quantity to be produced, actual quantity produced, percentage, total manufacturing cost for each month for each manufacturing unit and product to identify how each unit is performing
*/
transformed_varying_values_grpd = GROUP transformed_varying_valuesBY (GetMonth($0),manufacturing_unit_id,product_id);
quantity_produced = FOREACH transformed_varying_values_grpd 
{
  expected_quantity_produced =SUM(transformed_varying_values.expected_quantity_produced);
  actual_quantity_produced =SUM(transformed_varying_values.actual_quantity_produced);
  percentage_quantity_produced =100*actual_quantity_produced/expected_quantity_produced;
  manufacturing_cost =SUM(transformed_varying_values.manufacturing_cost);
  GENERATE group.$0 AS production_month,group.$1 ASmanufacturing_unit_id,group.$2 ASproduct_id,expected_quantity_produced ASexpected_quantity_produced,actual_quantity_produced ASactual_quantity_produced,percentage_quantity_produced ASpercentage_quantity_produced,ROUND(manufacturing_cost) ASmanufacturing_cost;
}

/*
Sort the relation by the percentage of quantity produced
*/
ordered_quantity_produced = ORDER quantity_produced BY $5 DESC;

/*
The results are stored on the HDFS in the directory data_integration
*/
STORE ordered_quantity_produced INTO '/user/cloudera/pdp/output/data_transformation/data_integration';

结果

以下是对输入执行代码后生成的结果片段:

6  2  C003  2400  2237	93  894800
10  2  C004  1984  1814  91  816300
12  3  L002  74400  66744  89  33372

第一列显示month,第二列为manufacturing unit id,第三列代表product idExpected quantity to be producedactual quantity producedpercentagetotal manufacturing cost per month;所有这些都是根据每个单位的月度表现来计算的。

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • Chapter5/code/
  • Chapter5/datasets/

聚合模式

聚合设计模式探索了 Pig 通过对数据应用聚合或聚合操作来转换数据的用法。

背景

聚合提供数据的汇总和高级视图。将多个属性聚合为一个属性,从而通过将一组记录视为单个记录或不关注不重要记录的子部分来减少记录总数。数据聚合可以在不同的粒度级别上执行。

数据聚合保持了数据的完整性,尽管结果数据集的体积比原始数据集小。

动机

数据聚合在大数据中起着关键作用,因为海量的数据本来就很难提供太多的整体信息。而是每天收集数据,然后汇总成周数据;每周的数据可以汇总成一个月的值,依此类推。此数据模式出现,可用于分析。一个简单的例子是细分年龄组,根据特定属性(如按年龄购买)获取特定群体的更多信息。这种使用特定属性聚合数据的能力可以快速为进一步分析提供有价值的见解。

有各种技术来聚合数据。聚合数据的基础技术有SUMAVGCOUNT;先进技术包括CUBEROLLUP

CUBEROLLUP在很多方面都很相似,都是汇总数据产生单个结果集。ROLLUP从小到大,计算不同级别的总量,如SUMCOUNTMAXMINAVG

CUBE使用所选列中所有可能的值组合,启用来计算SUMCOUNTMAXMINAVG。一旦在一组列上计算了此聚合,它就可以提供这些维度上所有可能的聚合问题的结果。

用例

您可以考虑使用这种设计模式来生成数据的汇总表示。我们将看几个需要用摘要或摘要信息替换数据的场景。这种聚合是在数据被发送进行分析和处理之前完成的。聚合设计模式可用于以下特定场景:

  • 包含交易信息的记录可以基于产品或交易日期等多个维度进行聚合。
  • 每个家庭成员的收入等个人信息可以概括为代表家庭平均收入。

模式实现

这个设计模式是作为一个独立的 Pig 脚本实现的。该脚本实现了使用 Pig 0 . 11 . 0 版本中引入的CUBEROLLUP运算符来聚合数据。

聚合是提取、转换、加载 ( ETL )中对转换阶段的数据进行的基本操作。聚合数据最快的方法是使用ROLLUPCUBE。在大多数情况下,ROLLUPCUBE提供最有意义的数据汇总。该脚本加载多个制造单元的生产数据。这些数据可以出于各种目的进行汇总。通过将ROLLUP应用于该数据,我们可以获得以下总量:

  • 每个制造单位每月每个产品的生产数量
  • 每个制造单元中每个产品在所有月份的生产数量
  • 每个制造单位的总生产量
  • 所有制造单位的总产量

通过将CUBE应用于同一数据集,除了前面的聚合之外,我们还获得了以下聚合:

  • 每个制造单位的月生产量
  • 每个产品每月的生产数量
  • 每种产品的生产数量
  • 每月生产数量

CUBE返回的其他四个聚合是其内置函数的结果,该函数可以为分组列的所有可能组合创建小计。

代码片段

为了说明该模型的工作原理,我们考虑存储在 HDFS 的制造数据集。它包含三个主要文件:manufacturing_units.csv包含每个制造单元的信息,products.csv包含制造产品的详细信息,manufacturing_units_products.csv保存不同制造单元制造的产品的详细信息。文件production.csv包含各制造单元的生产信息;该文件包含 T4、T5、T6、T7 和 T8 等属性。我们将在manufacturing_unit_idproduct_idproduction_month上应用CUBEROLLUP聚合,如下代码所示:

/*
Load the data from production.csv, manufacturing_units_products.csv, manufacturing_units.csv files into the relations production, manufacturing_units_products and manufacturing_units
The files manufacturing_units_products.csv and manufacturing_units.csv contain master data information.
*/
production = LOAD'/user/cloudera/pdp/datasets/data_transformation/production.csv' USING PigStorage(',') AS(production_date:datetime,production_hours:int,manufacturing_unit_id:chararray,product_id:chararray,produced_quantity:int);
manufacturing_units_products = LOAD'/user/cloudera/pdp/datasets/data_transformation/manufacturing_units_products.csv' USING PigStorage(',') AS(manufacturing_unit_id:chararray,product_id:chararray,capacity_per_hour:int,manufacturing_cost:float);
manufacturing_units = LOAD'/user/cloudera/pdp/datasets/data_transformation/manufacturing_units.csv' USING PigStorage(',') AS(manufacturing_unit_id:chararray,manufacturing_unit_name:chararray,manufacturing_unit_city:chararray,country:chararray,currency:chararray);

/*
The relations are joined to get details from the master data.
*/
production_join_manufacturing_units_products = JOIN production BY(manufacturing_unit_id,product_id), manufacturing_units_productsBY (manufacturing_unit_id,product_id);
manufacture_join = JOINproduction_join_manufacturing_units_products BYproduction::manufacturing_unit_id, manufacturing_units BYmanufacturing_unit_id;

/*
The manufacturing cost attribute is converted to dollars for the units that have currency as INR.
*/
transformed_varying_values = FOREACH manufacture_join GENERATE $2AS manufacturing_unit_id,$3 AS product_id,GetMonth($0) AS production_month,((($13 == 'INR') ? ($8/60) :$8)*$4) AS manufacturing_cost;

/*
Apply CUBE and ROLLUP aggregations on manufacturing_unit_id, product_id, production_month and store the results in the relations results_cubed and results_rolledup
*/
cubed = CUBE transformed_varying_values BYCUBE(manufacturing_unit_id,product_id,production_month);
rolledup = CUBE transformed_varying_values BYROLLUP(manufacturing_unit_id,product_id,production_month);
result_cubed = FOREACH cubed GENERATE FLATTEN(group),ROUND(SUM(cube.manufacturing_cost)) AS total_manufacturing_cost;
result_rolledup = FOREACH rolledup GENERATE FLATTEN(group),ROUND(SUM(cube.manufacturing_cost)) AS total_manufacturing_cost;

/*
The results are stored on the HDFS in the directories cube and rollup
*/
STORE result_cubed INTO'/user/cloudera/pdp/output/data_transformation/data_aggregation/cube';
STORE result_rolledup INTO'/user/cloudera/pdp/output/data_transformation/data_aggregation/rollup';

结果

manufacturing_unit_idproduct_idproduction_month应用ROLLUP后,产生以下结果组合:

  • 每个制造单位每月每个产品的生产数量如下:

    1  C001  1  536600
    5  C002  12  593610
    
  • 每个制造单位每个产品的月生产量如下:

    1  C001    7703200
    2  C003    10704000
    5  C002    7139535
    
  • 每个制造单元的总产量如下:

    1      15719450
    4      15660186
    
  • 所有制造单位的总产量如下:

          69236355
    

CUBE应用于manufacturing_unit_idproduct_idproduction_month后,除了ROLLUP生产的组合外,还获得了以下组合:

  • 每个制造单元的月生产量如下:

    1    4  1288250
    5    12  1166010
    
  • 每个产品每月的生产数量如下:

      C001  8  1829330
      L002  12  101748
      L001  10  36171
    
  • 每个产品的生产数量如下:

      C002    15155785
      C004    16830110
      L002    667864
    
  • 月生产量如下:

        2  5861625
        10  5793634
        11  5019340
    

如前所示,CUBEROLLUP多返回四个合计(每个制造单位的月生产量、每个产品的月生产量、每个产品的月生产量、每个产品的月生产量)。这是因为CUBE内置了为分组列的所有可能组合创建小计的功能。

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • Chapter5/code/
  • Chapter5/datasets/

数据泛化模式

数据泛化模式通过创建概念层次并将数据替换为这些层次来处理数据转换。

背景

这个设计模式通过一个 Pig 脚本探索数据泛化的实现。数据泛化是创建称为概念层次的顶层概要层的过程,它以一般形式描述底层数据概念。这是一种描述方法的形式,其中数据由分组,并使用概念层次结构由更高级别的类别或概念替换。例如,属性 age 的原始值可以用概念标签(如成人、青少年或儿童)或区间标签(0 到 5、13 到 19 等)来代替。).这些标签可以递归地组织成更高级的概念,从而产生属性的概念层次。

动机

大数据背景下,海量数据的典型分析流水线需要多个结构化和非结构化数据集的集成。

数据泛化过程通过使用简洁通用的方式描述的泛化数据,减少了 Hadoop 集群中待分析数据所占用的空间。数据摘要的过程不是对整个数据语料库进行分析,而是以概念层次的形式呈现数据的一般属性,有助于快速获得更广更小的分析趋势视图,并在多个抽象层次进行挖掘。

应用数据泛化可能会导致细节的丢失,但在某些分析案例中,泛化的数据更有意义,也更容易解释。

通过在顶层概念层次中组织数据,可以在多个数据分析管道中实现一致的数据表示。此外,对精简数据集的分析需要更少的输入/输出操作和更少的网络吞吐量,并且比对更大的非标准化数据集的分析更有效。

由于这些好处,数据泛化通常被用作分析之前的预处理步骤,而不是在挖掘期间。有各种技术用于对数值数据进行数据汇总,例如宁滨、直方图分析、基于熵的离散化、卡方分析、聚类分析和通过视觉分割的离散化。类似地,对于分类数据,可以基于定义层次的属性的不同值的数量来执行一般化。

用例

您可以考虑在分析场景中使用这种设计模式来生成数字和分类结构化数据的广义表示,其中需要用更高级别的汇总来概括数据,而不是用低级别的原始数据来实现一致性。

您也可以考虑在数据集成过程之后立即使用这种模式作为分析加速器,以创建更适合高效分析的简化数据集。

模式实现

这个设计模式是作为一个独立的 Pig 脚本实现的。该脚本根据每个属性的不同值生成分类数据的概念层次结构。

脚本对manufacturing_unit_productsproductscomponentsproduct_components的关系进行连接操作。然后从属性componentsproducts中选择不同的值,生成概念层次;属性按其不同的值以升序排序。这将根据排序顺序生成层次结构;第一个属性位于层次结构的顶部,最后一个属性位于层次结构的底部。

代码片段

主数据集components.csv包含组件详细信息,products_components.csv文件包含组件详细信息和制造产品所需的组件数量。该文件包含 T2、T3 和 T4 等属性。下面的代码是 Pig 脚本,它演示了这种模式的实现:

/*
Load products_components data set into the relation products_components
*/
products_components = LOAD'/user/cloudera/pdp/datasets/data_transformation/products_components.csv' USING PigStorage(',') AS(product_id:chararray,component_id:chararray,required_qty_per_Unit:int);

/*
Calculate the distinct count for product_id and component_id and store the results in the relations products_unique_count and components_unique_count
*/
products_components_grpd = GROUP products_components ALL;
products_unique_count = FOREACH products_components_grpd
{
  attribute_name = 'Products';
  distinct_prod = DISTINCT products_components.product_id;
  GENERATE attribute_name AS attribute_name, COUNT(distinct_prod)AS attribute_count; 
}
components_unique_count = FOREACH products_components_grpd
{
  attribute_name = 'Components'; 
  distinct_comp = DISTINCT products_components.component_id;
  GENERATE attribute_name AS attribute_name, COUNT(distinct_comp)AS attribute_count; 
}

/*
The relations product_unique_count and components_unique_count are combined using the UNION operator.
This relation contains two columns attribute_name and attribute_count, it is then sorted by attribute_count
*/
combined_products_components_count = UNIONproducts_unique_count,components_unique_count;
ordered_count = ORDER combined_products_components_count BYattribute_count ASC;

/*
The results are stored on the HDFS in the directory data_generalization
*/
STORE ordered_count INTO'/user/cloudera/pdp/output/data_transformation/data_generalization'; 

结果

以下是对分类数据进行归纳的结果:

Products    6
Components  18

结果显示attribute nameunique count;属性的计数排序。结果描述了概念层次。第一个属性Products在层次结构的顶部,最后一个属性Components在层次结构的底部。

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • Chapter5/code/
  • Chapter5/datasets/

总结

在本章中,您已经学习了各种大数据转换技术,这些技术处理将数据结构转换为分层表示,以利用 Hadoop 处理半结构化数据的能力。在分析数据之前,我们已经看到了标准化数据的重要性。然后,我们讨论使用连接来反规范化数据连接。CUBEROLLUP将数据聚合几次;这些聚合提供了数据的快照。在数据合成中,我们讨论了各种数字和分类数据的合成技术。

在下一章中,我们将重点介绍数据缩减技术。数据简化旨在获得数据的简化表示;它确保了数据的完整性,尽管获得的数据集的体积要小得多。我们将讨论数据约简技术,如降维、采样技术、宁滨和聚类。阅读本章后,您将能够选择正确的数据缩减模式。

六、理解数据简化模式

在前一章中,我们研究了各种大数据转换技术,这些技术处理了将数据结构转换为分层表示的问题。这是为了利用 Hadoop 处理半结构化数据的能力。在分析数据之前,我们已经看到了标准化数据的重要性。然后,我们讨论使用连接来反规范化数据。并且 CUBE 和 ROLLUP 对数据执行多次聚合;这些聚合提供了数据的快照。在数据合成部分,我们讨论了各种数值和分类数据的合成技术。

在这一章中,我们将讨论使用主成分分析技术的降维设计模式,以及使用聚类、采样和直方图技术的降维设计模式。

数据简化–快速介绍

数据简化旨在获得数据的简化表示。它确保了数据的完整性,尽管缩减后的数据集在体积上比原始数据集小得多。

数据简化技术分为以下三类:

  • 降维:这组数据降维技术处理的是减少分析问题中考虑的属性数量。他们通过检测和消除不相关的属性、相关但弱的属性或冗余属性来做到这一点。主成分分析和小波变换是降维技术的例子。
  • 数值约简:这套数据约简技术通过用数据的稀疏表示代替原始数据集来约简数据。数据的稀疏子集采用参数法计算,如回归,其中模型用于估计数据,因此只有一个子集就足够了,而不是整个数据集。还有其他方法,如非参数方法,如聚类、采样和直方图,无需建模即可工作。
  • 压缩:这组数据缩减技术使用算法来减少数据消耗的物理存储大小。通常,压缩在比属性或记录级别更高的粒度级别上执行。如果需要从压缩数据中检索原始数据而不丢失任何信息(这在存储字符串或数字数据时是必需的),请使用无损压缩方案。相反,如果视频和声音文件需要解压缩以适应难以察觉的清晰度损失,则使用有损压缩技术。

下图说明了上述组中使用的不同技术:

Data reduction – a quick introduction

数据简化技术-概述

大数据数据约简注意事项

在大数据问题中,数据约简技术必须被视为分析过程的一部分,而不是一个单独的过程。这将使您了解哪些类型的数据必须保留或删除,因为它们与建议的分析相关问题无关。

在典型的大数据分析环境中,数据通常是从多个来源获取和整合的。尽管使用整个数据集进行分析可能会获得隐藏的回报,这可能会产生更丰富、更好的见解,但成本有时会超过结果。正是在这种情况下,您可能不得不考虑减少数据量,而不会大大降低分析意见的有效性,这本质上是为了保护数据的完整性。

由于数据量巨大,对大数据执行任何类型的分析通常都会导致高昂的存储和检索成本。当数据很小时,数据约简过程的好处有时并不明显;当数据集开始变大时,它们开始变得明显。这些数据缩减过程是从存储和检索角度优化数据的第一步。重要的是要考虑数据约简的影响,这样在数据约简上花费的计算时间就不会超过或消除数据挖掘对约简后的数据集节省的时间。既然我们已经理解了数据缩减的概念,我们将在下面的小节中探索一些特定的设计模式。

降维-主成分分析设计模式

在这个设计模式中,我们会考虑使用主成分分析 ( 主成分分析)和奇异值分解 ( 奇异值分解)来实现降维,广泛用于探索性数据分析和预测创建。

背景

给定数据中的维度可以直观地理解为用来解释数据观测属性的所有属性的集合。降维意味着将高维数据转换成与数据的内在或潜在维度成比例的降维集合。这些潜在维度是描述数据集所需的最小属性数。因此,降维是一种理解数据隐藏结构的方法,用于缓解高维空间的诅咒等不必要的属性。

一般来说,降维有两种方式。一种是线性降维,如主成分分析和奇异值分解。二是非线性降维,以核主成分分析和多维标度为例。

在这种设计模式中,我们通过在 R 中实现 PCA 和在 Mahout 中实现 SVD 并将其与 Pig 集成来探索线性降维。

动机

我们先来概述一下 PCA。主成分分析(PCA)是一种线性降维技术,通过将数据集植入低维的子空间,对给定的数据集进行无监督的处理,这是通过构建原始数据的基于方差的表示来实现的。

主成分分析的基本原理是通过分析数据变化最大的方向或数据分布最广的方向来识别数据的隐藏结构。

直观地说,主成分可以认为是一条线,它穿过一组变化较大的数据点。如果让同一条线通过数据点,没有区别,说明数据是一样的,没有携带太多信息。在没有方差的情况下,数据点不被认为是整个数据集属性的代表,这些属性可以省略。

主成分分析包括寻找数据集的成对特征值和特征向量。给定的数据集被分解成多对特征向量和特征值。特征向量定义了单位向量或垂直于其他向量的数据方向。就是特征值数据在这个方向上的分布值。

在多维数据中,可以存在的特征值和特征向量的个数等于数据的维数。特征值最大的特征向量是主成分。

找出主成分后,按照特征值降序排序,这样第一个向量显示方差最高,第二个向量显示方差次高,以此类推。这些信息有助于发现以前没有被怀疑的隐藏模式,从而允许通常不会产生的解释。

由于数据现在按重要性降序排序,因此可以通过消除具有弱分量的属性或具有小数据方差的低重要性来减少数据大小。利用高值主成分,原始数据集可以构建一个良好的近似。

例如,考虑一个对 1 亿人的抽样选举调查,这些人被问了 150 个关于他们对选举相关问题的看法的问题。分析超过 150 个属性的 1 亿个答案是一项繁琐的任务。我们有一个 150 维的高维空间,从中产生 150 个特征值/向量。我们按照重要性降序排列特征值(例如,230,160,130,97,62,8,6,4,2,1 …最多 150 个维度)。从这些数值中,我们可以理解为可以有 150 个维度,但只有前 5 个维度有变化较大的数据。有了这个,我们可以把高维空间减少 150,在下一步的分析过程中考虑前五个特征值。

接下来我们来看看 SVD。奇异值分解与主成分分析密切相关有时两个术语都用作奇异值分解,这是实现主成分分析的一种更通用的方法。奇异值分解是矩阵分析的一种形式,它产生高维矩阵的低维表示。它通过移除线性相关数据来减少数据。和主成分分析一样,奇异值分解也利用特征值进行降维。该方法是将来自几个相关向量的信息组合成正交基向量,并解释数据中的大部分方差。

**例如,如果您有两个属性,一个是冰淇淋的销量,另一个是温度,它们之间的相关性非常高,以至于第二个属性“温度”不会提供任何对分类任务有用的附加信息。奇异值分解得到的特征值决定了哪些属性信息最丰富,哪些属性不能使用。

Mahout 的随机奇异值分解 ( ssvd ) 是基于分布式计算数学的奇异值分解。如果pca参数设置为真,SSVD 在主成分分析模式下运行;该算法计算输入列均值,然后用它计算主成分分析空间。

用例

可以考虑用这个模式进行数据约简和数据探索,作为聚类和多元回归的输入。

设计模式可以应用于稀疏和倾斜数据的有序和无序属性。它也可以用于图像。这种设计模式不能应用于复杂的非线性数据。

模式实现

以下步骤描述了使用 R 实现主成分分析:

  • 脚本使用主成分分析技术进行降维。主成分分析包括寻找数据集的特征值和特征向量对。特征值最大的特征向量是主成分。按组件特征值的降序排序。
  • 该脚本加载数据,并使用流调用 r 脚本。r 脚本对数据执行 PCA 并返回主成分。只能选择能够解释大部分变化的前几个主成分,从而降低了数据的维度。

主成分分析的局限性

虽然流允许你调用自己选择的可执行文件,但是会影响性能,在输入数据集很大的情况下,解决方案是不可伸缩的。为了克服这一点,我们提出了一种更好的利用 Mahout 进行降维的方法。它包含一组高度可扩展的机器学习库。

以下步骤描述了 SSVD 在 Mahout 上的实现:

  • 以 CSV 格式读取输入数据集,以键/值对的形式准备一组数据点;关键字应该是唯一的,值应该由 n 个向量元组组成。
  • 将之前的数据写入序列文件。按键可以是WritableComparableLong或者String类型,数值应该是VectorWritable类型。
  • 确定缩减空间的维度。
  • 在 Mahout 上使用rank参数执行 SSVD(这指定了尺寸),并将pcausV设置为真。当pca参数设置为真时,算法在主成分分析模式下运行,计算输入列均值,然后用它计算主成分分析空间。USigma文件夹包含缩小后的输出。

一般来说,降维应用于非常高维的数据集;然而,在我们的例子中,为了更好地解释,我们在较少维度的数据集上演示了这一点。

代码片段

为了说明该模型的工作原理,我们考虑存储在 Hadoop 文件系统 ( HDFS )中的零售交易数据集。包含Transaction IDTransaction dateCustomer IDProduct subclassPhone NoProduct IDagequantityassetTransaction AmountService RatingProduct RatingCurrent Stock等 20 个属性。对于这个模型,我们将使用主成分分析来降维。下面的代码片段是一个 Pig 脚本,它演示了通过 Pig 流实现这种模式:

/*
Assign an alias pcar to the streaming command
Use ship to send streaming binary files (R script in this use case) from the client node to the compute node
*/
DEFINE pcar '/home/cloudera/pdp/data_reduction/compute_pca.R' ship('/home/cloudera/pdp/data_reduction/compute_pca.R'); 

/*
Load the data set into the relation transactions
*/
transactions = LOAD '/user/cloudera/pdp/datasets/data_reduction/transactions_multi_dims.csv' USING  PigStorage(',') AS (transaction_id:long, transaction_date:chararray, customer_id:chararray, prod_subclass:chararray, phone_no:chararray, country_code:chararray, area:chararray, product_id:chararray, age:int, amt:int, asset:int, transaction_amount:double, service_rating:int, product_rating:int, curr_stock:int, payment_mode:int, reward_points:int, distance_to_store:int, prod_bin_age:int, cust_height:int);
/*
Extract the columns on which PCA has to be performed.
STREAM is used to send the data to the external script.
The result is stored in the relation princ_components
*/
selected_cols = FOREACH transactions GENERATE age AS age, amt AS amount, asset AS asset, transaction_amount AS transaction_amount, service_rating AS service_rating, product_rating AS product_rating, curr_stock AS current_stock, payment_mode AS payment_mode, reward_points AS reward_points, distance_to_store AS distance_to_store, prod_bin_age AS prod_bin_age, cust_height AS cust_height;
princ_components = STREAM selected_cols THROUGH pcar;

/*
The results are stored on the HDFS in the directory pca
*/
STORE princ_components INTO '/user/cloudera/pdp/output/data_reduction/pca';

下面是说明这种模式的实现的代码:

#! /usr/bin/env Rscript
options(warn=-1)

#Establish connection to stdin for reading the data
con <- file("stdin","r")

#Read the data as a data frame
data <- read.table(con, header=FALSE, col.names=c("age", "amt", "asset", "transaction_amount", "service_rating", "product_rating", "current_stock", "payment_mode", "reward_points", "distance_to_store", "prod_bin_age", "cust_height"))
attach(data)

#Calculate covariance and correlation to understand the variation between the independent variables
covariance=cov(data, method=c("pearson"))
correlation=cor(data, method=c("pearson"))

#Calculate the principal components
pcdat=princomp(data)
summary(pcdat)
pcadata=prcomp(data, scale = TRUE)
pcadata

下面的代码片段说明了使用 Mahout 的 SSVD 实现这个模式。以下是 shell 脚本的一个片段,其中包含执行 CSV 到序列转换器的命令:

#All the mahout jars have to be included in HADOOP_CLASSPATH before execution of this script. 
#Execute csvtosequenceconverter jar to convert the CSV file to sequence file.
hadoop jar csvtosequenceconverter.jar com.datareduction.CsvToSequenceConverter /user/cloudera/pdp/datasets/data_reduction/transactions_multi_dims_ssvd.csv /user/cloudera/pdp/output/data_reduction/ssvd/transactions.seq

以下是 Pig 脚本的代码片段,其中包含在 Mahout 上执行 SSVD 的命令:

/*
Register piggybank jar file
*/
REGISTER '/home/cloudera/pig-0.11.0/contrib/piggybank/java/piggybank.jar';

/*
*Ideally the following data pre-processing steps have to be generally performed on the actual data, we have deliberately omitted the implementation as these steps were covered in the respective chapters

*Data Ingestion to ingest data from the required sources

*Data Profiling by applying statistical techniques to profile data and find data quality issues

*Data Validation to validate the correctness of the data and cleanse it accordingly

*Data Transformation to apply transformations on the data.
*/

/*
Use sh command to execute shell commands.
Convert the files in a directory to sequence files
-i specifies the input path of the sequence file on HDFS
-o specifies the output directory on HDFS
-k specifies the rank, i.e the number of dimensions in the reduced space
-us set to true computes the product USigma
-V set to true computes V matrix
-pca set to true runs SSVD in pca mode
*/

sh /home/cloudera/mahout-distribution-0.8/bin/mahout ssvd -i /user/cloudera/pdp/output/data_reduction/ssvd/transactions.seq -o /user/cloudera/pdp/output/data_reduction/ssvd/reduced_dimensions -k 7 -us true -V true -U false -pca true -ow -t 1

/*
Use seqdumper to dump the output in text format.
-i specifies the HDFS path of the input file
*/
sh /home/cloudera/mahout-distribution-0.8/bin/mahout seqdumper -i /user/cloudera/pdp/output/data_reduction/ssvd/reduced_dimensions/V/v-m-00000

结果

以下是通过 Pig 流执行 R 脚本的结果片段。为了提高可读性,只显示结果的重要部分。

Importance of components:
                             Comp.1      Comp.2       Comp.3
Standard deviation     1415.7219657 548.8220571 463.15903326
Proportion of Variance    0.7895595   0.1186566   0.08450632
Cumulative Proportion     0.7895595   0.9082161   0.99272241

下图显示了结果的图形表示:

Results

主成分分析输出

从累积的结果来看,我们可以用前三个组成部分来解释大部分的变化。因此,我们可以去掉其他组件,仍然解释大部分数据,从而实现数据约简。

以下是在 Mahout 上应用 SSVD 后获得的结果的代码片段:

Key: 0: Value: {0:6.78114976729216E-5,1:-2.1865954292525495E-4,2:-3.857078959222571E-5,3:9.172780131217343E-4,4:-0.0011674781643860148,5:-0.5403803571549012,6:0.38822546035077155}
Key: 1: Value: {0:4.514870142377153E-6,1:-1.2753047299542729E-5,2:0.002010945408634006,3:2.6983823401328314E-5,4:-9.598021198119562E-5,5:-0.015661212194480658,6:-0.00577713052974214}
Key: 2: Value: {0:0.0013835831436886054,1:3.643672803676861E-4,2:0.9999962672043754,3:-8.597640675661196E-4,4:-7.575051881399296E-4,5:2.058878196540628E-4,6:1.5620427291943194E-5}
.
.
Key: 11: Value: {0:5.861358116239576E-4,1:-0.001589570485260711,2:-2.451436184622473E-4,3:0.007553283166922416,4:-0.011038688645296836,5:0.822710349440101,6:0.060441819443160294}

V文件夹的内容显示了原始变量对每个主成分的贡献。结果是一个 12×7 的矩阵,因为在我们的原始数据集中有 12 个维度,根据 SSVD 秩参数,这些维度被减少到 7 个。

USigma文件夹包含缩小尺寸的输出。

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • Chapter6/code/
  • Chapter6/datasets/

关于 Mahout 实现 SSVD 的信息可以在以下链接中找到:

递减数值-直方图设计模式

数值化简-直方图设计模式探索 直方图技术在数据化简中的实现。

背景

直方图属于数据约简的数值约简范畴。它们是非参数数据约简方法,其中假设数据不适合预定义的模型或函数。

动机

直方图的工作原理是将整个数据划分成桶或组,存储每个桶的中心趋势。在内部,这类似于宁滨。直方图可以通过动态编程进行优化。直方图不同于条形图,因为它们代表连续的数据类别,而不是离散的类别。这意味着直方图中代表不同类别的列之间没有间隙。

直方图通过将大量连续属性分组来帮助减少数据的类别。表示大量属性可能会导致复杂的直方图,有太多的列来解释信息。因此,数据被分组到一个范围中,该范围代表属性值的连续范围。数据可以按以下方式分组:

  • 等宽分组技术:在这个分组技术中,每个区间都是等宽的。
  • 等频(或等深)分组技术:在等频分组技术中,以每个范围的频率恒定或每个范围包含相同数量的连续数据元素的方式创建范围。
  • V-最优分组技术:在这个分组技术中,我们考虑给定范围内所有可能的直方图,选择方差最小的直方图。
  • Maxdiff 分组技术:这种直方图分组技术根据每对相邻值之间的差异考虑将值分组到一个范围内。边界被定义在具有最大差异的每对相邻点之间。下图描述了根据 9-14 和 18-27 之间的最大差异分为三个范围的分类数据。

Motivation

最大差异-图标

在前面提到的分组技术中,V-Optimal 和 MaxDiff 技术对于接近稀疏和密集的数据以及高度偏斜和均匀的数据更加准确和有效。这些直方图也可以通过使用多维直方图来处理多个属性,多维直方图可以捕捉属性之间的依赖关系。

用例

这种设计模式在以下情况下可以考虑:

  • 当数据不适用于回归或对数线性模型等参数模型时
  • 当数据是连续的而不是离散的时
  • 当数据具有有序或无序的数字属性时
  • 当数据倾斜或稀疏时

模式实现

脚本加载数据,并使用等宽分组将数据分成桶。Transaction Amount字段的数据被分组到桶中。它计算每个存储桶中的事务数量,并返回存储桶范围和计数作为输出。

这种模式产生了数据集的简化表示,其中事务量被划分为指定数量的桶,事务计数在这个范围内。这些数据被绘制成直方图。

代码片段

为了解释这个模型是如何工作的,我们考虑存储在 HDFS 的零售交易数据集。包含 T0、T1、T2、T3、T4、T5、T6、T7、T8、T9 等属性。对于这个模式,我们将在属性Transaction Amount上生成桶。下面的代码片段是一个 Pig 脚本,演示了这种模式的实现:

/*
Register the custom UDF
*/
REGISTER '/home/cloudera/pdp/jars/databucketgenerator.jar';

/*
Define the alias generateBuckets for the custom UDF, the number of buckets(20) is passed as a parameter
*/
DEFINE generateBuckets com.datareduction.GenerateBuckets('20');

/*
Load the dataset into the relation transactions
*/
transactions = LOAD '/user/cloudera/pdp/datasets/data_reduction/transactions.csv' USING  PigStorage(',') AS (transaction_id:long,transaction_date:chararray, cust_id:chararray, age:chararray, area:chararray, prod_subclass:int, prod_id:long, quantity:int, asset:int, transaction_amt:double, phone_no:chararray, country_code:chararray);

/*
Maximum value of transactions amount and the actual transaction amount are passed to generateBuckets UDF
The UDF calculates the bucket size by dividing maximum transaction amount by the number of buckets.
It finds out the range to which each value belongs to and returns the value along with the bucket range
*/
transaction_amt_grpd = GROUP transactions ALL;
transaction_amt_min_max = FOREACH transaction_amt_grpd GENERATE MAX(transactions.transaction_amt) AS max_transaction_amt,FLATTEN(transactions.transaction_amt) AS transaction_amt;
transaction_amt_buckets = FOREACH transaction_amt_min_max GENERATE generateBuckets(max_transaction_amt,transaction_amt) ;

/*
Calculate the count of values in each range
*/
transaction_amt_buckets_grpd = GROUP transaction_amt_buckets BY range;
transaction_amt_buckets_count = FOREACH transaction_amt_buckets_grpd GENERATE group, COUNT(transaction_amt_buckets);

/*
The results are stored on HDFS in the directory histogram.
*/
STORE transaction_amt_buckets_count INTO '/user/cloudera/pdp/output/data_reduction/histogram';

下面的代码片段是 Java UDF 代码,演示了这种模式的实现:

@Override
  public String exec(Tuple input) throws IOException {
    if (input == null || input.size() ==0)
      return null;
    try{
      //Extract the maximum transaction amount
      max = Double.parseDouble(input.get(0).toString());
      //Extract the value
      double rangeval = Double.parseDouble(input.get(1).toString());
      /*Calculate the bucket size by dividing maximum 
        transaction amount by the number of buckets.
      */
      setBucketSize();

      /*Set the bucket range by using the bucketSize and 
        noOfBuckets
      */
      setBucketRange();

      /*
      It finds out the range to which each value belongs 
      to and returns the value along with the bucket range
      */
      return getBucketRange(rangeval);
    } catch(Exception e){
      System.err.println("Failed to process input; error - " + e.getMessage());
      return null;
    }

结果

以下是将该模式应用于数据集的结果片段;第一列是Transaction Amount属性的时间范围,第二列是交易计数:

1-110        45795
110-220      50083
220-330      60440
330-440      40001
440-550      52802

下面是使用 gnuplot 绘制这些数据时生成的直方图。它以图形方式显示了交易金额期间和每个期间的交易数量。

Results

输出直方图

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • Chapter6/code/
  • Chapter6/datasets/

递减数值-抽样设计模式

这个设计模式探索了数据约简的采样技术的实现。

背景

采样 属于数据约简的数值约简范畴。它可以用作数据缩减技术,因为它使用小得多的子集来表示大量数据。

动机

采样本质上是一种数据约简方法,确定具有整体种群特征的种群的近似子集。抽样是一种选择数据子集以准确代表人口的通用方法。采样通过各种方法执行,这些方法定义子集的内容,并以不同的方式定位子集的候选项。

在大数据场景下,分析整个群体的成本(比如分类、优化)非常高;采样有助于降低成本,因为它减少了用于执行实际分析的数据空间,然后根据整体情况推断结果。准确性会略有下降,但这远远超过了减少时间和存储之间权衡的好处。

说到大数据,无论统计抽样技术应用在哪里,识别要分析的人都很重要。即使收集到的数据非常大,样本也可能只与人口中的一小部分相关,并不代表全部。在选择样本时,代表性起着至关重要的作用,因为它决定了抽样数据与总体的接近程度。

可以使用概率和非概率方法进行采样。下图显示了采样技术的概况:

Motivation

抽样法

概率抽样方法使用随机抽样,总体中的每个元素都有已知的非零(大于零)机会被选入抽样子集中。概率抽样方法利用加权抽样得到总体的无偏样本。以下是一些概率抽样方法:

  • 简单随机抽样:这是最基本的抽样类型。在这个抽样中,群体中的每个元素都有同等的机会被选入一个子集。样本是客观随机选取的。简单的随机抽样可以通过替换总体中的选定项目,以便它们可以被再次选择(带替换的抽样)或通过不替换总体中的选定项目(不带替换的抽样)来完成。随机抽样并不总是产生有代表性的样本,在非常大的数据集上执行这种操作是一种昂贵的操作。采用分层或聚类的方法对人群进行预抽样,可以提高随机抽样的代表性。

  • The following diagram illustrates the difference between the Simple Random Sampling Without Replacement (SRSWOR) and Simple Random Sampling With Replacement (SRSWR).

    Motivation

    斯沃弗 vs 斯沃弗

  • 分层抽样:这个抽样技术是在我们已经知道种群包含很多独特的类别时使用的,用来将种群组织成子种群(地层);然后可以从中选择一个样本。所选样本必须包含每个子群体的元素。这种抽样方法侧重于相关的子组,而忽略了不相关的子组。通过消除绝对随机性,增加了样本的代表性,这一点可以通过简单的随机抽样和从独立类别中选择项目来证明。当预先确定地层的独特类型时,分层抽样是一种更有效的抽样技术。分层有一个总的时间成本权衡,因为最初为相对同质的人识别独特的类别可能很无聊。

  • 非概率抽样:这种抽样方法选择的是人群的一个子集,但并没有给人群中的某些元素同样的选择机会。在这种抽样中,不能准确确定选择元素的概率。元素的选择纯粹是基于对感兴趣的人的一些假设。非概率抽样得分太低,无法准确代表总体,因此无法将分析从样本外推至总体。非概率抽样方法包括协方差抽样、判断抽样和定额抽样。

用例

您可以考虑在以下场景中使用数字下采样设计模式:

  • 当数据是连续的或离散的时
  • 当数据的每个元素都有同等的机会被选择而不影响抽样的代表性时
  • 当数据具有有序或无序的属性时

模式实现

这个设计模式在 Pig 中作为独立脚本实现。它使用datafu库,把 SRSWR 的实现看成是一对 UDF、SimpleRandomSampleWithReplacementElectSimpleRandomSampleWithReplacementVote;他们为 SRSWR 实现了一个可扩展的算法。该算法包括投票和选举两个阶段。每个职位的候选人在投票阶段投票。在选举阶段,每个职位选举一名候选人。输出是一包采样数据。

该脚本使用 SRSWR 技术从交易数据集中选择 100,000 条记录的样本。

代码片段

为了说明 T10 模型的工作原理,我们考虑存储在 HDFS 的零售交易数据集。包含 T0、T1、T2、T3、T4、T5、T6、T7、T8、T9 等属性。在这种模式下,我们将对事务数据集执行 SRSWR。下面的代码片段是一个 Pig 脚本,演示了这种模式的实现:

/*
Register datafu and commons math jar files
*/
REGISTER '/home/cloudera/pdp/jars/datafu-1.2.0.jar';
REGISTER '/home/cloudera/pdp/jars/commons-math3-3.2.jar';

/*
Define aliases for the classes SimpleRandomSampleWithReplacementVote and SimpleRandomSampleWithReplacementElect
*/
DEFINE SRSWR_VOTE  datafu.pig.sampling.SimpleRandomSampleWithReplacementVote();
DEFINE SRSWR_ELECT datafu.pig.sampling.SimpleRandomSampleWithReplacementElect();

/*
Load the dataset into the relation transactions
*/
transactions= LOAD '/user/cloudera/pdp/datasets/data_reduction/transactions.csv' USING  PigStorage(',') AS (transaction_id:long,transaction_date:chararray, cust_id:chararray, age:int, area:chararray, prod_subclass:int, prod_id:long, quantity:int, asset:int, transaction_amt:double, phone_no:chararray, country_code:chararray);

/*
The input to Vote UDF is the bag of items, the desired sample size (100000 in our use case) and the actual population size.
  This UDF votes candidates for each position
*/
summary = FOREACH (GROUP transactions ALL) GENERATE COUNT(transactions) AS count;
candidates = FOREACH transactions GENERATE FLATTEN(SRSWR_VOTE(TOBAG(TOTUPLE(*)), 100000, summary.count));

/*
The Elect UDF elects one candidate for each position and returns a bag of sampled items stored in the relation sampled
*/
sampled = FOREACH (GROUP candidates BY position PARALLEL 10) GENERATE FLATTEN(SRSWR_ELECT(candidates));

/*
The results are stored on the HDFS in the directory sampling
*/
STORE sampled into '/user/cloudera/pdp/output/data_reduction/sampling';

结果

以下是采样交易数据后得到的结果片段。为了提高可读性,我们删除了一些列。

580493 … 1621624 … … … … 1 115 576 900-435-5791 U.S.A
193016 … 1808643 … … … … 1 119 735 9020138550 U.S.A
800748 … 199995 … … … … 1 28 1577 904-066-467q USA

结果是一个包含 100,000 条记录的文件,作为原始数据集的样本。

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • Chapter6/code/
  • Chapter6/datasets/

减量-集群设计模式

这种设计模式探索了聚类技术在数据约简中的实现。

背景

聚类 属于数据约简的数值约简范畴。聚类是一种非参数模型,它使用无监督学习在没有类别标签先验知识的情况下工作。

动机

聚类是解决数据分组问题的一种通用方法。这可以通过各种算法来实现,这些算法在定义什么进入一个组以及如何找到该组的候选人方面是不同的。聚类算法有 100 多种不同的实现方式,可以针对不同的目标解决各种问题。对于给定的问题,没有单一的规模适合所有的聚类算法;我们必须通过仔细的实验选择正确的。适用于特定数据模型的聚类算法并不总是适用于不同的模型。聚类广泛应用于机器学习、图像分析、模式识别和信息检索。

聚类的目标是基于一组启发式算法对数据集进行划分,并有效地减小其大小。集群在某种程度上类似于宁滨,因为它模仿了宁滨的分组方法;然而,区别在于聚类中分组的精确方式。

分区的实现方式是一个集群中的数据与同一个集群中的另一个数据相似,但与其他集群中的其他数据不同。这里,相似性被定义为数据彼此有多接近的度量。

K-means 是应用最广泛的聚类方法之一。用聚类分析的 k 种方法将观测值分成 k 个聚类;这里,每个观测值都属于平均值最近的聚类。这是一个迭代过程,只有当集群质心不再移动时,这个过程才会稳定。

可以通过测量每个聚类对象距聚类质心的直径或平均距离来确定聚类执行得如何的质量度量。

通过一家服装公司计划向市场发布新 t 恤的例子,我们可以直观地理解聚类减少数据量的必要性。如果公司不使用数据还原技术,最终会做出不同尺寸的 t 恤来迎合不同的人。为了防止这种情况,他们减少了数据。首先,他们记录了人们的身高和体重,绘制在图表上,并将其分为三类:小、中、大。

K-Means 方法使用身高和体重的数据集( n 个观测值)并将其划分为 k (即三个聚类)。对于每个聚类(小、中、大),聚类中的数据点更接近聚类类别(即小身高、小体重的平均值)。K Means 为我们提供了三种最适合每个人的尺寸,从而有效降低了数据的复杂度;集群使我们能够自己替换实际数据,而不是处理实际数据。

我们已经考虑使用 Mahout 的 K-Means 实现;更多信息可从https://mahout . Apache . org/users/clustering/k-means-clustering . html获取。

从大数据的角度来看,由于需要处理大量的数据,在选择聚类算法时需要考虑时间和质量的权衡。正在进行新的研究,以开发一种能够高效处理大数据的预聚类方法。然而,预聚类方法的结果是原始数据集的近似预划分,最终将通过传统方法(如 K-means)再次聚类。

用例

这种设计模式在以下情况下可以考虑:

  • 当数据是连续的或离散的并且数据的类别标签事先未知时
  • 当需要通过聚类对数据进行预处理并最终对大量数据进行分类时
  • 当数据具有数字、有序或无序属性时
  • 当数据是绝对的
  • 当数据不偏斜、稀疏或模糊时

模式实现

设计模式在 Pig 和 Mahout 中实现。数据集被载入 Pig。要对其执行 K 均值聚类的年龄属性被转换成向量,并以 Mahout 可读格式存储。它将 Mahout 的 K 均值聚类应用于事务数据集的年龄属性。k 均值聚类将观测值划分为 k 个聚类,其中每个观测值都属于均值最近的聚类;只有当聚类质心不再移动时,该过程才是迭代和稳定的。

该模式产生数据集的简化表示,其中age属性被分成预定数量的簇。该信息可用于识别光顾该商店的顾客的年龄组。

代码片段

为了说明的工作原理,我们考虑存储在 HDFS 的零售交易数据集。包含 T0、T1、T2、T3、T4、T5、T6、T7、T8、T9 等属性。对于这种模式,我们将对age属性进行 K 均值聚类。下面的代码片段是一个 Pig 脚本,演示了这种模式的实现:

/*
Register the required jar files
*/
REGISTER '/home/cloudera/pdp/jars/elephant-bird-pig-4.3.jar';
REGISTER '/home/cloudera/pdp/jars/elephant-bird-core-4.3.jar';
REGISTER '/home/cloudera/pdp/jars/elephant-bird-mahout-4.3.jar';
REGISTER '/home/cloudera/pdp/jars/elephant-bird-hadoop-compat-4.3.jar';
REGISTER '/home/cloudera/mahout-distribution-0.7/lib/json-simple-1.1.jar';
REGISTER '/home/cloudera/mahout-distribution-0.7/lib/guava-r09.jar';
REGISTER '/home/cloudera/mahout-distribution-0.7/mahout-examples-0.7-job.jar'; 
REGISTER '/home/cloudera/pig-0.11.0/contrib/piggybank/java/piggybank.jar';

/*
Use declare to create aliases.
declare is a preprocessor statement and is processed before running the script
*/
%declare SEQFILE_LOADER 'com.twitter.elephantbird.pig.load.SequenceFileLoader';
%declare SEQFILE_STORAGE 'com.twitter.elephantbird.pig.store.SequenceFileStorage';
%declare VECTOR_CONVERTER 'com.twitter.elephantbird.pig.mahout.VectorWritableConverter';
%declare TEXT_CONVERTER 'com.twitter.elephantbird.pig.util.TextConverter';

/*
Load the dataset into the relation transactions
*/
transactions = LOAD '/user/cloudera/pdp/datasets/data_reduction/transactions.csv' USING  PigStorage(',') AS (id:long,transaction_date:chararray, cust_id:int, age:int, area:chararray, prod_subclass:int, prod_id:long, quantity:int, asset:int, transaction_amt:double, phone_no:chararray, country_code:chararray);

/*
Extract the columns on which clustering has to be performed
*/
age = FOREACH transactions GENERATE id AS tid, 1 AS index, age AS cust_age;

/*
Generate tuples from the parameters
*/
grpd = GROUP age BY tid;
vector_input = FOREACH grpd generate group, org.apache.pig.piggybank.evaluation.util.ToTuple(age.(index, cust_age));
/*
Use elephant bird functions to store the data into sequence file (mahout readable format)
cardinality represents the dimension of the vector.
*/
STORE vector_input INTO '/user/cloudera/pdp/output/data_reduction/kmeans_preproc' USING $SEQFILE_STORAGE (
 '-c $TEXT_CONVERTER', '-c $VECTOR_CONVERTER -- -cardinality 100'
);

下面的是一个 shell 脚本的片段,其中包含对 Mahout 执行 K-means 聚类的命令:

#All the mahout jars have to be included in classpath before execution of this script.
#Create the output directory on HDFS before executing VectorConverter
hadoop fs -mkdir /user/cloudera/pdp/output/data_reduction/kmeans_preproc_nv

#Execute vectorconverter jar to convert the input to named vectors
hadoop jar /home/cloudera/pdp/data_reduction/vectorconverter.jar com.datareduction.VectorConverter /user/cloudera/pdp/output/data_reduction/kmeans_preproc/ /user/cloudera/pdp/output/data_reduction/kmeans_preproc_nv/

#The below Mahout command shows the usage of kmeans. The algorithm takes the input vectors from the path specified in the -i argument, it chooses the initial clusters at random, -k argument specifies the number of clusters as 3, -x specified the maximum number of iterations as 15\. -dm specifies the distance measure to use i.e euclidean distance and a convergence threshold specified in -cd as 0.1
/home/cloudera/mahout-distribution-0.7/bin/mahout kmeans -i /user/cloudera/pdp/output/data_reduction/kmeans_preproc_nv/ -c kmeans-initial-clusters -k 3 -o /user/cloudera/pdp/output/data_reduction/kmeans_clusters -x 15 -ow -cl -dm org.apache.mahout.common.distance.EuclideanDistanceMeasure -cd 0.01

# Execute cluster dump command to print information about the cluster
/home/cloudera/mahout-distribution-0.7/bin/mahout clusterdump --input /user/cloudera/pdp/output/data_reduction/kmeans_clusters/clusters-4-final --pointsDir /user/cloudera/pdp/output/data_reduction/kmeans_clusters/clusteredPoints --output age_kmeans_clusters

结果

以下是在事务数据集上应用该模式的结果片段:

VL-817732{n=309263 c=[1:45.552] r=[1:4.175]}
  Weight : [props - optional]:  Point:
1.0: 1 = [1:48.000]
  1.0: 2 = [1:42.000]
  1.0: 3 = [1:42.000]
  1.0: 4 = [1:41.000]
VL-817735{n=418519 c=[1:32.653] r=[1:4.850]}
  Weight : [props - optional]:  Point:
  1.0: 5 = [1:24.000]
  1.0: 7 = [1:38.000]
  1.0: 12 = [1:34.000]
  1.0: 14 = [1:23.000]
VL-817738{n=89958 c=[1:65.198] r=[1:5.972]}
  Weight : [props - optional]:  Point:
  1.0: 6 = [1:66.000]
  1.0: 8 = [1:58.000]
  1.0: 16 = [1:62.000]
  1.0: 24 = [1:74.000]

VL-XXXXXX是收敛聚类的聚类标识,c是质心和向量,n是聚类的点数,r是半径和向量。根据 K-means 命令,数据被分为三个簇。当这个数据被可视化时,我们可以推断 41 和 55 之间的值被分组在组 1 下,20 和 39 被分组在组 2 下,56 和 74 被分组在组 3 下。

附加信息

本节的完整代码和数据集位于以下 GitHub 目录中:

  • Chapter6/code/
  • Chapter6/datasets/

总结

在本章中,您学习了各种旨在获得数据简化表示的数据简化技术。我们探索了使用主成分分析技术降维和使用聚类、采样和直方图技术降维的设计模式。

在下一章中,您将探索用 Pig 模拟社交媒体数据的高级模型,并使用文本分类和其他相关技术来更好地理解上下文。我们也将了解未来 PIG 语将如何演变。**

七、高级模式和未来工作

在前一章中,您已经学习了各种旨在减少分析或处理的数据量的大数据缩减技术。我们探索了使用主成分分析技术降维和使用聚类、采样和直方图技术降维的设计模式。

在本章中,我们将从讨论主要处理文本数据的设计模式开始,并探索使用 Pig 作为关键的输入和处理引擎可以构建的各种分析管道。

我们将深入研究以下模式:

  • 文本数据聚类
  • 发现主题
  • 自然语言处理
  • 分类

我们也将推测 PIG 设计模式的未来。这些未来趋势分析了主流中遵循的趋势,以针对特定用例修改 Pig。包括这些趋势将从哪里产生,什么样的数据趋势将影响当前的设计模式,等等。

聚类模式

聚类设计模式通过计算集合的相似度,用 Pig 和 Python 对结果进行聚类,探索文本聚类。

背景

在的前一章中,我们研究了如何使用聚类作为数据约简技术。我们探索了一种处理数字数据的聚类技术。

文本聚类自动将相关文档分组为彼此相似的聚类,并将不同的文档划分为不同的聚类。执行聚类的主要原因是,如果文档语料库被聚类,我们划分搜索空间,以便可以在包含相关文档的聚类上执行搜索。聚类是提高搜索有效性和效率的重要途径之一。一组文档是否相似或不同并不总是很清楚,但通常会随着实际问题而变化。例如,在对研究文章进行聚类时,如果任何两篇文章共享相似的主题,则认为它们相似。在对网站进行聚类时,我们感兴趣的是根据网页包含的信息类型对网页进行聚类。例如,为了将大学网站聚集在一起,我们可能希望将教授的主页与学生的主页分开,并将课程页面与研究项目页面分开。

文本聚类适用于我们需要将多个文本文档组织成标记整齐的类别,使信息检索更加容易的情况。它还可以用于文本语料库的自动摘要,这样我们就可以对语料库的全部内容有一个大致的了解。

文本数据具有许多独特的属性,因此有必要设计一种特殊的分类算法。以下是文本表示的一些显著特征:

  • 文本表示通常是非常高维的,但是底层数据是稀疏的。换句话说,从中提取文档的字典可能包含一百万个单词,但是给定的文档可能只包含几百个单词。
  • 这些词通常是相互关联的,这意味着主要成分(或重要概念)比词少。
  • 每个文档中的单词数量差异很大,因此需要根据单词向量在文档和整个集合中的相对频率对其进行标准化。这通常通过计算项频率-逆文档频率 ( TF-IDF )来实现。
  • 当我们需要对短句或推文进行聚类时,这些问题的影响更大。

聚类在从社交媒体对话中检索重要见解方面发挥着关键作用,这些对话主要是非结构化的,数量巨大。由于社交媒体内容由一个客户生成并交付给其他客户,因此内容生成的速度也是选择聚类机制时需要考虑的因素。社交媒体不仅限于微博平台上的 Twitter 和社交网络平台上的脸书单独创作的内容;维基、论坛、博客和其他媒体共享平台经常创建各种其他内容源。这些平台主要创建文本内容,除了 Flickr 和 YouTube,它们创建图像和视频数据。对各种类型的社交媒体内容进行聚类提供了对文档、图像、视频、网络链接和其他上下文信息之间的关系相似性的内在理解。

在这种设计模式中,我们将自己局限于对从社交媒体收集的文本数据进行聚类,这样如果我们自己的社交网络中有相似的人,我们就可以从数据中进行解释。这种相似性可能是由于相同的头衔、公司或地点。

动机

有各种算法常用于文本聚类。我们有层次聚类和基于距离的聚类技术,它们使用相似性函数来衡量任何两个文本对象之间的接近程度。许多聚类算法主要在相似性度量的计算方法上有所不同。下图描述了最常见的文本数据聚类技术:

Motivation

基于的常见文本聚类算法

以下是对最常见的文本聚类技术的简要描述:

  • Hierarchical Agglomerative Clustering (HAC): This technique is useful for supporting a variety of problems that arise while searching because it creates a tree hierarchy that can be leveraged for the search process and improves the search effectiveness and efficiency.

    HAC 算法的一般概念是根据文档与其他文档的相似性,将文档组合成簇。层次聚类算法根据文档组之间的最佳成对相似度不断地组合组。使用流行的距离度量(如欧几里德、曼哈顿和莱文斯坦)来计算文档中不同点集之间的相似度。这分别对应于单连锁、群体平均连锁和完全连锁聚类。这些算法相当精确,但缺乏效率。

  • 基于距离的划分算法:这些算法一般是用来创建一个聚类对象的,其中层次结构并没有起到重要的作用。有两种广泛使用的基于距离的聚类算法:K-med oid 和 K-means。这些算法远不如 HAC 算法精确,但效率要高得多。

    • K- 水母聚类算法:这种技术使用一组来自原始数据的 K 数据点作为中心点(或水母),围绕这个中心点展开聚类。该算法的中心目标是从原始文档集中找到一组理想的文档,并围绕这些文档构建一个聚类。每个文档都被分配给集合中与其最接近的文档。这将从文档集中创建一个迭代集群,并通过随机过程不断改进它。K-med oid 聚类算法的主要缺点是速度慢,因为需要大量迭代才能实现收敛,并且不适合稀疏文本数据集。
    • K-means 聚类算法:这个技术和 K-medoids 非常相似,因为它也使用了一组 K 数据点来围绕这些数据点构建聚类。然而,与 K-med oid 不同,这组初始代表点不是从原始数据中获得的。代表点的初始集合从诸如分层聚类和部分监督的方法中获得。K-means 算法比 K-medoids 算法更快,因为它在更少的迭代中收敛。使用 K-means 方法的缺点是严重依赖于初始种子集的准确性,给定文档簇的质心可能包含大量单词。

Pig 用于摄取源数据,并将几个标准转换应用于术语向量表示。

  1. 删除停止字。这些词对于文档的主题来说是不可描述的(例如,a、an、is 和)。
  2. 使用波特的词干分析器对单词进行词干分析,以便将不同词尾的单词映射到一个单词中。
  3. 衡量文档中包含的稀有词对整体聚类能力的影响,然后决定丢弃频率低于指定阈值的词。

以下是一些字符串相似性度量的快速概述,这些度量用于计算用于聚类的字符串的接近度:

  • 编辑距离或莱文斯坦距离:这个通过计算将一个字符串转换成另一个字符串所需的最小替换次数来计算字符串的相异度
  • Jaccard 相似度 : 这是通过将两个集合之间的公共项目数除以两个集合中不同项目的总数来计算的。
  • 度量集值项目(masi) 的一致性:当集合之间存在部分重叠时,该距离返回的距离比 Jaccard 相似度短。

用例

集群设计模式可用于以下目的:

  • 检索后,对数据进行聚类,以便向用户呈现更有条理的结果。
  • 基于文档的相似性为浏览目的创建文档的分层分类。

模式实现

该模式中描述的用例将具有相似标题的 Outlook 联系人聚集在一起。从概念上讲,该模型可以根据任何标准(如职位)识别哪些联系人是相似的。例如,这个模型可以扩展到回答你的哪些联系人在你想工作的公司工作过,或者你的大多数联系人在哪里。

Pig 脚本加载数据,通过用完整形式替换缩写来转换数据,并通过流将不同的作业传递给 Python 脚本。传递不同的职称可以确保发送到 Python 脚本的数据量减少。

大多数集群代码都是用 Python 实现的,Python 对集群有现成的支持。Python 脚本在简化阶段通过流调用。《PIG 传》标题从stdin开始用 Python 脚本读取,计算 MASI 距离。基于距离和阈值对标题进行聚类,然后将聚类后的标题写入stdout

Pig 脚本将 Python 写入的值读入stdout,通过从 Pig 关系中可用的数据中获取标题来执行名称和标题之间的关联。

我们探索了几种计算 levenshtein 的方法,以便在这种模式下聚集作业和集中 MASI 距离。这个距离度量被认为适合我们当前的用例,其中标题重叠。

代码片段

为了说明模式的工作原理,我们已经将联系人姓名及其标题从 Outlook 导出到一个 CSV 文件中,并对姓名进行了识别。该文件存储在 HDFS。

所有不在默认 Python 路径中的外部 Python 模块都应该在脚本执行之前添加到PYTHONPATH环境变量中。

下面的代码片段是一个 Pig 脚本,演示了这种模式的实现:

 /*
Assign alias cluster_contacts to the streaming command
Use SHIP to send the streaming binary files (Python script) from the client node to the compute node
*/
DEFINE cluster_contacts 'cluster_contacts.py' SHIP ('cluster_contacts.py');

/*
Register the piggybank jar file
*/
REGISTER '/home/cloudera/pig-0.11.0/contrib/piggybank/java/piggybank.jar';

/*
Load the outlook_contacts.csv dataset into the relation outlook_contacts
*/
outlook_contacts = LOAD '/user/cloudera/pdp/datasets/advanced_patterns/outlook_contacts.csv' USING PigStorage(',') AS (name: chararray, job_title: chararray);

/*
Transform the job titles by replacing few abbreviations with their full forms
*/
transformed_job_titles = FOREACH outlook_contacts {
job_title_sr = REPLACE(job_title,'Sr', 'Senior');

.
.
job_title_vp = REPLACE(job_title_cfo,'VP', 'Vice President');

GENERATE name AS name,job_title_vp AS job_title;
}

/*
Trim spaces for the field job_title
*/
jt_trimmed = FOREACH transformed_job_titles GENERATE TRIM(job_title) AS job_title,name;

/*
Group outlook_contacts by job_title
Extract unique job titles and store into the relation jt_flattened
STREAM is used to send the data to the external script
The Python script executes as a reduce job as STREAM is called after GROUP BY
The result is stored in the relation clustered_jt
*/
jt_trimmed_grpd = GROUP jt_trimmed BY job_title;
jt_flattened = FOREACH jt_trimmed_grpd GENERATE flatten(group);
clustered_jt = STREAM jt_flattened THROUGH cluster_contacts;

/*
Clustered job titles from relation clustered_jt are typecasted to chararray and are assigned to relation clustered_jt_cast.
clustered_jt_cast relation contains job title clusters.  
*/
clustered_jt_cast = FOREACH clustered_jt GENERATE (chararray)$0 AS cluster;

/*
The job titles are tokenized by using comma and are assigned to the relation clustered_jt_tokens along with the cluster name.
*/
clustered_jt_tokens  = FOREACH clustered_jt_cast GENERATE TOKENIZE(cluster,','), cluster;

/*
Each job title in job cluster is converted into a new tuple and is assigned to relation clustered_jt_flattened along with the cluster name.
*/
clustered_jt_flattened = FOREACH clustered_jt_tokens  GENERATE FLATTEN($0) AS cluster_job, cluster;

/*
Trim spaces in the job titles.
*/
clustered_jt_trimmed  = FOREACH clustered_jt_flattened GENERATE TRIM(cluster_job) AS cluster_job, cluster;

/*
Join jt_trimmed relation by job_title with the relation clustered_jt_trimmed by cluster_job. Project the contact name and cluster name.
*/
jt_clustered_joind = JOIN jt_trimmed BY job_title,clustered_jt_trimmed  BY cluster_job;
name_clustered_jt = FOREACH jt_clustered_joind GENERATE jt_trimmed::name AS name, clustered_jt_trimmed::cluster AS cluster;

/*
Remove duplicate tuples from relation name_clustered_jt.
*/
uniq_name_clustered_jt  = DISTINCT name_clustered_jt;

/*
Group the relation uniq_name_clustered_jt by field cluster and project the cluster name(consisting of a set of job titles) and the contact name
*/
name_clustered_jt_grpd =  GROUP uniq_name_clustered_jt  BY cluster;
similar_jt_clusters= FOREACH name_clustered_jt_grpd GENERATE group AS clustername, uniq_name_clustered_jt.name AS name;

/*
The results are stored on the HDFS in the directory clustering
*/
STORE similar_jt_clusters into '/user/cloudera/pdp/output/advanced_patterns/clustering';

下面的是一个 Python 代码片段,说明了这个模式的实现:

#! /usr/bin/env python

# Import required modules 
import sys
import csv
from nltk.metrics.distance import masi_distance

# Set the distance function to use and the distance threshold value 
DISTANCE_THRESHOLD = 0.5
DISTANCE = masi_distance

def cluster_contacts_by_title():

# Read data from stdin and store in a list called contacts
    contacts = [line.strip() for line in sys.stdin]
    for c in contacts[:]:
        if len(c)==0 :
            contacts.remove(c)

# create list of titles to be clustered (from contacts list) 
    all_titles = []
    for i in range(len(contacts)):
        title = [contacts[i]]
        all_titles.extend(title)

    all_titles = list(set(all_titles))

    # calculate masi_distance between two titles and cluster them based on the distance threshold, store them in dictionary variable called clusters
    clusters = {}
    for title1 in all_titles:
        clusters[title1] = []
        for title2 in all_titles:
            if title2 in clusters[title1] or clusters.has_key(title2) and title1 \
                in clusters[title2]:
                continue
            distance = DISTANCE(set(title1.split()), set(title2.split()))
            if distance < DISTANCE_THRESHOLD:
                clusters[title1].append(title2)

    # Flatten out clusters
    clusters = [clusters[title] for title in clusters if len(clusters[title]) > 1]

    # Write the cluster names to stdout
    for i in range(len(clusters)):
        print ", ".join(clusters[i])

结果

下面的是在数据集上以这种模式执行代码后的结果片段。为了提高可读性,我们只显示了几个集群。左边以逗号分隔的列表显示了汇总的职务,而与职务相关联的名称显示在右边。

IT Analyst, IT Financial Analyst    {(Name268),(Name869)}
Delivery Head, Delivery Unit Head    {(Name631),(Name662)}
Data Scientist, Lead Data Scientist    {(Name50),(Name823),(Name960),(Name314),(Name124),(Name163),(Name777),(Name58),(Name695)}
Lead Analyst, Lead Business Analyst    {(Name667),(Name495),(Name536),(Name952)}
Pega Practice Head, M2M Practice Head    {(Name618),(Name322)}
Technical Lead, Lead Technical Writer    {(Name52),(Name101),(Name120),(Name969),(Name683)}
Vice President, Vice President Sales    {(Name894),(Name673),(Name72)}
Business Analyst, Lead Business Analyst    {(Name536),(Name847)}
Director - Presales, Director - Staffing    {(Name104),(Name793)}
Product Manager, Senior. Product Manager    {(Name161),(Name956)}
Technology Lead, Technology Lead Service    {(Name791),(Name257)}

在下图中,我们用图形表示了几个集群,以提高可读性:

Results

集群输出

如上图所示,第一个集群由两个联系人组成,头衔分别为大数据科学家-架构师数据架构师-大数据。这两个标题相似,因此联系人被分组到一个集群中。

附加信息

本节的完整代码和数据集可以在以下 GitHub 目录中找到:

  • Chapter7/code/
  • Chapter7/datasets/

话题发现模式

主题发现设计模式通过名为潜在狄利克雷分配 ( LDA ) 的技术,探索一种利用 Pig 和 Mahout 对文本语料库进行分类的方法。

背景

在文本语料库中发现隐藏主题是自然语言处理领域的最新发展之一。社交媒体网站上发布的数据通常涵盖广泛的主题。然而,为了从这些网站中提取相关信息,我们必须根据隐藏在文本中的主题的相关性对文本语料库进行分类。这将实现对大量文本的自动摘要,找到真正的内容。这样发现的主题的先验知识被用来对新文档进行分类。

动机

主题模型的关键难点是在没有任何内容先验知识的情况下,对文本语料库进行分类并识别其主题。先验知识意味着文档之前没有被标记为属于特定主题。主题模型使用统计方法来发现隐藏在文本语料库中的主题。

潜在狄利克雷赋值 ( LDA )是主题模型的实现,其工作原理是从文档中包含的一组词中识别主题,然后将文档分组为主题组合。

LDA 使用 TF-向量空间模型根据单词的上下文而不是频率来识别单词的含义。使用线性判别分析通过消除歧义来解决单词的含义。LDA 利用语境线索将意义相同的词联系起来,区分具有多重意义的词的用法。

我们可以通过考虑一个案例来形成对主题模型的直观理解。在这种情况下,人类很容易理解“青霉素”和“抗生素”这两个词在关于医学的文档中出现的频率更高,而“代码”和“调试器”这两个词在关于软件的文档中出现的频率更高。主题模型试图基于主题的词分布和文档分布从语料库中收集主题。

让我们考虑以下说法:

  • 我早餐吃了燕麦和胡萝卜。
  • 我喜欢橘子和胡萝卜。
  • 小狗小猫很可爱。
  • 我哥哥带了一只小狗回家。
  • 这只可爱的兔子正在嚼胡萝卜。

LDA 自动发现这些句子中包含的话题。例如,如果我们对这些句子执行 LDA 并查询发现的主题,输出可能如下:

Topic A: 30% oats, 15% carrots, 10% breakfast, 10% chewing, … (this topic could be interpreted to be about food)
Topic B: 20% Puppies, 20% kittens, 20% cute, 15% rabbit, ... (this topic could be interpreted to be about cute animals)
Sentences 1 and 2: 100% Topic A
Sentences 3 and 4: 100% Topic B
Sentence 5: 60% Topic A, 40% Topic B

Pig 是连接原始数据和 LDA 算法的粘合剂。它对数据进行预处理,并将其转换为适合 LDA 算法的格式。它可以轻松快速地从各种来源获取正确的数据,对其进行清理,并将其转换为必要的格式。Pig 根据原始数据制作数据集,并发送给 LDA 实现脚本。

用例

您可以考虑在非结构化文本语料库中使用这种设计模式来探索潜在的意图和摘要。当我们不知道文本语料库的内容,不能基于监督分类算法进行分类时,也可以考虑这个模型,这样我们甚至可以理解潜在的主题。

模式实现

为了实现这种模式,我们考虑了一组关于大数据和医学的文章,我们打算在文档中找到内在的主题。这种设计模式在 Pig 和 Mahout 中实现。阐述了一种实现 Pig 和 Mahout 集成的方法,以缓解数据矢量化并转换为 Mahout 可读格式的问题,从而实现快速原型制作。我们特意省略了预处理和向量转换的步骤,因为我们已经在的第 6 章【理解数据约简模式】中看到了说明这些步骤的例子。

shPig 中的命令用于调用 Mahout 命令。这些命令执行预处理,创建稀疏向量,并应用折叠变分贝叶斯 ( CVB ) ,这是 Mahout 主题建模的 LDA 实现。返回每个主题的单词及其概率的结果列表。

代码片段

为了解释这个模型是如何工作的,我们考虑一个数据集,其中有两篇关于大数据和医学的文章。这些文件储存在 HDFS。对于这个模型,我们将对文本语料库应用主题建模来识别主题。

下面的代码片段是 Pig 代码,它演示了这种模式的实现:

/*
Register piggybank jar file
*/
REGISTER '/home/cloudera/pig-0.11.0/contrib/piggybank/java/piggybank.jar';

/*
*Ideally the following data pre-processing steps have to be generally performed on the actual data, we have deliberately omitted the implementation as these steps were covered in the respective chapters

*Data Ingestion to ingest data from the required sources

*Data Profiling by applying statistical techniques to profile data and find data quality issues

*Data Validation to validate the correctness of the data and cleanse it accordingly

*Data Transformation to apply transformations on the data.

*Data Reduction to obtain a reduced representation of the data.
*/

/*
We have deliberately omitted the steps for vector conversion as we have an example illustrating these in the chapter Understanding Data Reduction Patterns. 
*/

/*
Use sh command to execute shell commands.
Convert the files in a directory to sequence files
-i specifies the input directory on HDFS
-o specifies the output directory on HDFS
*/
sh /home/cloudera/mahout-distribution-0.8/bin/mahout seqdirectory -i /user/cloudera/pdp/datasets/advanced_patterns/lda -o /user/cloudera/pdp/output/advanced_patterns/lda/sequence_files

/*
Create sparse vectors
-i specifies the input directory on HDFS
-o specifies the output directory on HDFS
-nv to get the named vectors
*/
sh /home/cloudera/mahout-distribution-0.8/bin/mahout seq2sparse -i /user/cloudera/pdp/output/advanced_patterns/lda/sequence_files -o /user/cloudera/pdp/output/advanced_patterns/lda/sparse_vectors -nv -wt tf

/*
Use rowid to convert the sparse vectors by changing the text key to integer
-i specifies the input directory on HDFS
-o specifies the output directory on HDFS
*/
sh /home/cloudera/mahout-distribution-0.8/bin/mahout rowid -i /user/cloudera/pdp/output/advanced_patterns/lda/sparse_vectors/tf-vectors/ -o /user/cloudera/pdp/output/advanced_patterns/lda/matrix

/*
Use Collapsed Variational Bayes for topic modelling
-i specifies the input directory on HDFS
-o specifies the output directory on HDFS
-k specifies the number of topics
-x specifies the maximum number of iterations
-dict specifies the path to term dictionary
-dt specifies the path to document topic distribution
-mt specifies temporary directory of the model, this is useful when restarting the jobs
*/
sh /home/cloudera/mahout-distribution-0.8/bin/mahout cvb -i /user/cloudera/pdp/output/advanced_patterns/lda/matrix/matrix -o /user/cloudera/pdp/output/advanced_patterns/lda/lda-out -k 2 -x 5 -dict /user/cloudera/pdp/output/advanced_patterns/lda/sparse_vectors/dictionary.file-* -dt /user/cloudera/pdp/output/advanced_patterns  /lda/lda-topics -mt /user/cloudera/pdp/output/advanced_patterns/  lda/lda-model

/*
Display top ten words along with their probabilities for each topic
-i specifies the input directory on HDFS
-d specifies the path to the dictionary file
-dt specifies the type of the dictionary (sequence / text)
-sort sorts the Key/Value pairs in descending order
*/
sh /home/cloudera/mahout-distribution-0.8/bin/mahout vectordump -i /user/cloudera/pdp/output/advanced_patterns/lda/lda-out -d /user/cloudera/pdp/output/advanced_patterns/lda/sparse_vectors/dictionary.file-* -dt sequencefile -vs 10 -sort /user/cloudera/pdp/output/advanced_patterns/lda/lda-out

结果

以下是在数据集上以此模式执行代码后的结果片段:

Topic 1: {examination:0.11428571430112491,medical:0.09999999999299336,follow:0.057142857068596745,may:0.057142857068595974,patient:0.05714285706859565,order:0.05714285706858435,tests:0.042857142760463936,physical:0.04285714276045852,signs:0.04285714276044089,other:0.028571428452333902}
Topic 2:
  {data:0.14754098319799064,parallel:0.0983606554177082,processing:0.08196721282428095,mapreduce:0.08196721282428092,big:0.06557377023085392,framework:0.06557377023085392,architecture:0.06557377023085391,use:0.032786885044002005,end:0.032786885044002005,type:0.032786885044002005}

之前的结果表明,在文档中找到了两个主题(Topic 1Topic 2)以及每个主题的前十个单词及其概率列表。这些主题与大数据和医学有关。

附加信息

本节完整的代码和数据集可以在以下 GitHub 目录中找到:

  • Chapter7/code/
  • Chapter7/datasets/

More information about the realization of abomasum moving to the left by the elephant can be found in https://mahout. Apache. Organization/user/cluster/latent-dirty-allocation.html found.

自然语言处理模式

这种设计模式探索了使用 Pig 实现对非结构化文本数据的自然语言处理。

背景

信息从非结构化数据(如博客和文章)中检索围绕着从大量未注释的文本中提取有意义的信息。信息检索的核心目标是从非结构化文本中提取结构化信息。结构化信息被编入索引以优化搜索。例如,考虑以下句子:

"格雷厄姆·贝尔于 1876 年发明了电话."

前一句用于提取以下结构化信息:

Inventorof (Telephone, Graham Bell)
InventedIn(Telephone, 1876)

从文本语料库中检索信息的方法有很多。我们研究了基于 TF-IDF 的词包模型如何通过访问章节、章节、数据分析模式、非结构化文本分析模式中词频繁的文档,帮助将文档分解为词频,使信息检索成为可能。这种基于 TF-IDF 的模型的一个明显缺点是不需要对数据进行深入的语义理解。相反,这些模型侧重于用空格分隔的单词的语法,将文档分成一袋单词,并使用频率和简单的相似性度量来确定哪些单词在数据中可能很重要。虽然这些技术被广泛应用于各种应用中,但是当我们必须检索处理数据上下文的信息时,它们会失败。

以为例,生物医学研究人员经常查阅大量医学出版物,收集与基因、蛋白质或其他生物医学实体相关的发现。为了实现这一目标,简单的带有关键词匹配的搜索(如 TF-IDF)可能还不够,因为很多生物医学实体都有同义词和歧义名称;这使得准确检索相关文档变得困难。基于语义或上下文从文本中识别生物医学实体,并将它们链接到现有知识库中相应的条目,是生物医学文献挖掘的一项关键任务。在这个设计模式中,我们将探索使用 Pig 和 Python 从非结构化语料库中提取命名实体。

动机

使用自然语言处理对数据进行上下文敏感分解的两个基本任务称为实体识别和关系提取。

命名实体识别是一种技术,用于从非结构化文本中识别奥巴马、总统和华盛顿等实体的名称,并将它们分类为预定义的类型,如人员、工作和地点。命名实体识别通常不能通过字符串匹配来执行,因为给定类型的实体可以是无限的,并且命名实体的类型可以是上下文相关的。在上例中,实体“Washington”可以属于实体类型“Location”或“person”;为了正确确定正确的实体类型,必须考虑其上下文。命名实体识别是信息抽取的基本任务。其他信息结构(如关系和事件)的提取取决于命名实体识别作为预处理步骤的准确性。

命名实体识别一般通过统计序列标注算法来实现,如最大熵模型、隐马尔可夫模型和条件随机场。

以下是执行命名实体识别所涉及的高级步骤:

Motivation

命名实体识别

以下是 NLP 管道中涉及的步骤的简要描述:

  • 句末检测:这是语料库处理的第一步。它在整个文本语料库上执行,以将其分割成有意义的句子集。这一步克服了句末检测中涉及的歧义,在句末检测中,句号或其他标点符号表示句末和其他缩写。
  • 标记:这个对简单的句子进行操作,并将它们转换成标记。
  • 词性标注:这个给每个标注分配关于词性的信息(比如名词、动词和形容词)。在这一步中作为结果列出的词类将被分组在一起(例如,所有名词都可以分组)。这种分组最终将有助于对它们所属的实体类型(例如,人员、地点和组织)进行推理。
  • 阻塞:这个执行寻找名词组、动词组等一系列任务,把句子分成不同类型的组。
  • 提取:这个分析每个组块,标记为实体类型,比如人、地点、组织。

提取实体的上述步骤使我们能够使用这些实体作为分析的基础,而不是涉及关键词搜索和频率分析的以文档为中心的分析。这种分析的一个简单方法是从文档中提取所有名词和名词短语,并将它们作为出现在文档中的实体进行索引。

在这种设计模式中,Pig 用于摄取源数据,并在应用自然语言处理算法和识别词性或实体之前对其进行预处理。

用例

该设计模式可用于解决以下问题领域的需求:

  • 从新闻或其他文本语料库中提取金融或生物医学信息
  • 提取实体以自动汇总文本,并通过组合来自多个文档的信息来创建新文本。
  • 检测文本中的一些序列,这是聚类或索引文本之前所必需的。

模式实现

为了实现模型,我们考虑一个包含一些电话发明文本的文本数据集。代码的目标是从文档中提取命名实体。

这种设计模式是通过集成 Pig 和 Python 实现的。Python 通过其 NLTK 工具包对处理自然语言提供了广泛的支持。Pig 脚本加载一个文本文件,并通过流将这种关系传递给 Python 脚本。Python 的NLTK库内置了标记句子和单词的功能。其pos_tag功能是为每个令牌标记词性;Block 操作查找名词和动词组,并用实体类型(如人员、组织和地点)标记它们。Python 脚本使用NLTK库的这些功能,并将命名实体返回给 Pig 脚本。

代码片段

为了说明该模型的工作原理,我们考虑了从维基百科关于电话发明的文章中提取的文本数据集。该文件存储在 HDFS。对于这种模式,我们将使用 Pig 和 Python 来提取命名实体。

所有不在默认 Python 路径中的外部 Python 模块都应该在脚本执行之前添加到PYTHONPATH环境变量中。

下面的代码片段是 Pig 代码,它演示了这种模式的实现:

 /*
Assign alias ner to the streaming command
Use SHIP to send the streaming binary files (Python script) from the client node to the compute node
*/
DEFINE ner 'named_entities.py' SHIP ('named_entities.py');

/*
Load the dataset into the relation data
*/
data = LOAD '/user/cloudera/pdp/datasets/advanced_patterns/input.txt';

/*
STREAM is used to send the data to the external script
The result is stored in the relation extracted_named_entities
*/
extracted_named_entities = STREAM data THROUGH ner;

/*
The results are stored on the HDFS in the directory nlp
*/
STORE extracted_named_entities INTO '/user/cloudera/pdp/output/advanced_patterns/nlp';

下面的代码片段是说明这种模式实现的 Python 代码:

 #! /usr/bin/env python

# Import required modules 

import sys
import string
import nltk

# Read data from stdin and store it as sentences
for line in sys.stdin:
    if len(line) == 0: continue
    sentences = nltk.tokenize.sent_tokenize(line)

    # Extract words from sentences
    words = [nltk.tokenize.word_tokenize(s) for s in sentences]

    # Extract Part of Speech from words
    pos_words = [nltk.pos_tag(t) for t in words]

    # Chunk the extracted Part of Speech tags
    named_entities = nltk.batch_ne_chunk(pos_words)

    # Write the chunks to stdout
    print named_entities[0]

结果

下面的是在数据集上以这种模式执行代码后的结果片段。标签NNP表示名词是名词短语的一部分,VBD表示动词是简单过去式,JJ表示形容词。有关标签的更多信息,请参考佩恩树库项目,该项目提供了完整的摘要。以下是返回的词性标记的片段:

(S
 (PERSON Alexander/NNP)
 (PERSON Graham/NNP Bell/NNP)
 was/VBD
 awarded/VBN
 a/DT
 patent/NN
 for/IN
 the/DT
 electric/JJ
 telephone/NN
 by/IN
 (ORGANIZATION USPTO/NNP)
 in/IN
 March/NNP
 1876/CD
 ./.)

为了提高可读性,我们重新绘制了结果,如下图所示:

Results

命名实体标识输出

词性标注是对每个单词进行的。亚历山大·格雷厄姆·贝尔认人,词性标注完成为 NNP(名词短语的名词部分),代表专有名词。USPTO 被确定为一个组织,并被标记为专有名词。

附加信息

本节的完整代码和数据集可以在以下 GitHub 目录中找到:

  • Chapter7/code/
  • Chapter7/datasets/

See http://www.ling for other part-of-speech tagging information. upen。 Edu/ Course/Fall 2003/Ling 001/ Pennsylvania Tree Bank. html .

分类模式

这个设计模式探索了使用 Pig 和 Mahout 来实现分类。

背景

分类是预测分析的核心概念之一。这是一种技术,其中数据根据其特征被标记为类别或组。分类是一种基于数据及其属性进行决策的简化方法。例如,在调查问卷中,我们为给定的问题选择适当的答案或选中特定的复选框。在这里,我们从提供给我们的一组有限的选择(复选框或答案)中做出决定。有时,选择的数量可以少至两个(是/否)。在这些情况下,分类使用关于输入数据的特定信息来从一组预定响应中选择单个输出。

考虑一个人类决定购买比萨饼的例子。该决策的输入数据包括多个披萨的价格、配料、皮型等,预定选项组包括不买。查看输入信息,选择购买披萨(如果适合他的口味,在他的具体价格限制内),帮助分类相关人员做出有效决策。

利用机器学习进行分类,可以训练机器学习算法模仿人类思维,根据输入数据的特点进行自动决策。当这些算法必须根据特定的输入特征从分类值的短列表中决定单个输出时,它们工作得最好。

使用分类的预测分析的一个众所周知的例子是垃圾邮件检测,其中机器学习算法使用标记为垃圾邮件的过去电子邮件的细节,并将它们与电子邮件消息的属性相结合来决定新消息是垃圾邮件还是非垃圾邮件。类似地,在信用卡欺诈检测的情况下,欺诈交易的过去历史和当前交易的属性被用来确定交易是否是欺诈的。

所有分类算法都学习如何根据例子(过去的数据)做出决策。决策的准确性取决于输入分类算法示例的准确性和输入数据的质量。

动机

分类是一个三步走的过程:培训测试生产。培训和测试是生产前的步骤,历史数据用于构建和改进模型。这个数据已经被贴上了决策的标签(说垃圾或者不是垃圾)。历史数据分为两个桶,一个用于构建训练模型,另一个用于测试。训练数据约为历史数据的 80%到 90%,其余为测试数据。测试桶中的决定被故意删除。

  • 训练:训练步骤的输入由标记有已知决策的样本数据组成。基于已知的决策和输入数据特征,训练好的模型在测试步骤中执行分类。训练模型是分类引擎中最重要的工件。通过向其提供适当标记的样本数据,可以对其进行调整,以尽可能准确地进行预测。

  • 测试:测试步骤的输入是上一步的训练模型加上训练步骤中保留的新例子,有意删除决策。作为测试步骤的结果,模型选择一个决策并评估这些决策的准确性。这种评估是通过将已知结果与模型结果进行比较来完成的。这一步将影响模型的性能,模型将被相应地修改。一旦模型按预期运行,它将被部署到生产中,在那里将给出更多未标记的示例。

  • Production: The input to the production step is a set of new example data whose decision is unknown. The model deployed in production uses the inference formed out of the training and testing phase to perform the actual classification. The output of this phase is generally in line with the precision of the results obtained in the testing phase unless there is a drastic change in the input values or poor data quality. Occasionally, the samples of the production data are taken to be used as new training data so that the classification model is updated and deployed back into production.

    Motivation

    分类过程

分类练习的表现可以通过混淆矩阵来理解。混淆矩阵包含模型做出的决策值(预测类)和实际决策值(实际类)。它通常有两行两列,分别报告真阳性、假阴性、假阳性和真阴性的数量。混淆矩阵的列表示预测的类,行表示实际的类。

例如,如果模型需要将电子邮件分类为SPAMNOT_A_SPAM,文档实际上是SPAM,但模型将其分类为NOT_A_SPAM,那么混淆矩阵如下:

Motivation

混淆矩阵

在前面的混淆矩阵图中,对角线包含模型正确分类的电子邮件计数,而非对角线包含错误分类的示例。一个完美的分类器会正确地对所有项目进行分类,所以对角线上会有所有的计数。

分类可以使用各种算法进行。这些算法各有千秋,这取决于它所能处理的输入数据类型(如倾斜数据和均匀数据)、数据量、结果的可解释性、属性数量(具有高维空间)、分类器数量(如二进制是/否或多分类器)、训练和分类速度、并行性等等。

下图显示了最重要的分类算法的快照。对于给定的问题集,这些算法在有效性、效率和适用性方面有不同的权衡。

Motivation

几种分类算法

Pig 是生产中实现分类流水线的一种非常有用的语言。它派上了用场。它可以快速探索数据,分配正确的模式,从各种来源获取正确的数据,对其进行清理,整合数据并将其转换为必要的格式。Pig 根据原始数据制作一个数据集,以便对这个现成的数据集进行分类。

用例

设计模式可用于解决以下问题领域的需求,但不限于此:

  • 垃圾邮件过滤
  • 欺诈检测
  • 情感分析

模式实现

这个设计模式在 Pig 和 Mahout 中实现。阐述了一种实现 Pig 和 Mahout 集成的方法,以缓解数据矢量化并转换为 Mahout 可读格式的问题,从而实现快速原型制作。我们特意省略了预处理和向量转换的步骤,因为我们已经在的第 6 章【理解数据约简模式】中看到了说明这些步骤的例子。

一般来说,在向 Mahout 发送数据之前,可以使用 Pig 脚本来应用数据分析、验证和清理以及转换和约简步骤。在我们的用例中,我们假设数据已经被分析、清理和转换。

数据以 80:20 的比例分为训练数据和测试数据。训练数据用于训练模型,测试数据用于测试模型的预测精度。决策树模型以训练数据为基础,应用于测试数据。结果矩阵显示了预测结果和实际结果之间的比较。

代码片段

为了解释这个模型的工作原理,我们考虑了 UCI 格式的德国信用数据集。共有 20 个属性(7 个数字属性和 13 个分类属性)和 1000 个实例。该文件存储在 HDFS。对于这个模型,我们将使用 Pig 和 Mahout 对模型进行训练,根据一组属性将人分为好客户或坏客户;然后将根据测试数据对预测进行测试。

以下是 Pig 脚本,它演示了这种模式的实现:

 /*
Register piggybank jar file
*/
REGISTER '/home/cloudera/pig-0.11.0/contrib/piggybank/java/piggybank.jar';

/*
*The following data pre-processing steps have to be performed here, we have deliberately omitted the implementation as these steps were covered in the respective chapters
*Data Ingestion to ingest data from the required sources
*Data Profiling by applying statistical techniques to profile data and find data quality issues
*Data Validation to validate the correctness of the data and cleanse it accordingly
*Data Transformation to apply transformations on the data.
*Data Reduction to obtain a reduced representation of the data.
*/

/*
We have deliberately omitted the steps for vector conversion as we have an example illustrating these in the chapter Understanding Data Reduction Patterns. 
*/

/*
Use sh command to execute shell commands.
Generate file descriptor for the training dataset
The string C N 2 C N 2 C N 2 C N C N 2 C N C N 2 C L provides the description of the data.
C specifies that the first attribute is Categorical, it is followed by N specifying the next attribute to be Numeric. This is followed by 2 C which means that the next two attributes are Categorical.
L represents the Label
*/
sh hadoop jar /home/cloudera/mahout-distribution-0.8/core/target/mahout-core-0.8-job.jar org.apache.mahout.classifier.df.tools.Describe -p /user/cloudera/pdp/datasets/advanced_patterns/german-train.data -f /user/cloudera/pdp/datasets/advanced_patterns/german-train.info -d C N 2 C N 2 C N 2 C N C N 2 C N C N 2 C L

/*
Build Random Forests
-t specifies the number of decision trees to build
-p specifies usage of partial implementation
-sl specifies the number of random attributes to select for each node
-o specifies the output directory
-d specifies the path to the training dataset
-ds specifies the data descriptor
-Dmapred.max.split.size indicates the maximum size of each partition
*/
sh hadoop jar /home/cloudera/mahout-distribution-0.8/examples/target/mahout-examples-0.8-job.jar org.apache.mahout.classifier.df.mapreduce.BuildForest -Dmapred.max.split.size=1874231 -d /user/cloudera/pdp/datasets/advanced_patterns/german-train.data -ds /user/cloudera/pdp/datasets/advanced_patterns/german-train.info -sl 5 -p -t 100 -o /user/cloudera/pdp/output/advanced_patterns/classification

/*
Predict the label in the test dataset
-i specifies the file path of the test dataset
-ds specifies the dataset descriptor, we use the one generated for training data as the data description is the same for both training and test data
-m specifies the file path of the decision tree built on the training data
-a specifies that confusion matrix has to be calculated
-mr specifies usage of Hadoop to distribute the classification
-o specifies the output directory
*/
sh hadoop jar /home/cloudera/mahout-distribution-0.8/examples/target/mahout-examples-0.8-job.jar org.apache.mahout.classifier.df.mapreduce.TestForest -i /user/cloudera/pdp/datasets/advanced_patterns/german-test.data -ds /user/cloudera/pdp/datasets/advanced_patterns/german-train.info -m /user/cloudera/pdp/output/advanced_patterns/classification -a -mr -o /user/cloudera/pdp/output/advanced_patterns/classification_pred

结果

以下快照显示了在数据集上以此模式执行代码后的结果:

Results

决策树输出

前面的矩阵显示了预测结果和实际结果之间的比较。我们可以看到,该模型正确预测了 154 个实例,但错误地分类了 46 个实例。混淆矩阵显示,60 例中,22 例被正确归类为不良客户,38 例被错误归类为良好客户。同样,在 140 个案例中,132 个被正确归类为好客户,8 个被错误归类为坏客户。

附加信息

本节的完整代码和数据集可以在以下 GitHub 目录中找到:

  • Chapter7/code/
  • Chapter7/datasets/

See https://mahout for information on classification by using the elephant man. Apache. Organization/user/material/partial realization. html .

未来趋势

当我开始写这本书时,PIG 的用法发展很快。与 Pig 集成的新使用模式、新功能和新系统的知识正被各个行业和学术界定期推向公共领域。这些发展将对本书探讨的 PIG 设计模式产生直接影响。新技术的采用也将促进用户社区通过分享新模式和成熟的现有模式来记录 Pig 设计模式。

数据驱动模式的出现

在本书中,我们广泛讨论了 Pig 设计模式在传统企业环境中的使用。由于物联网现象的增长,未来大有可为。未来,物联网将使世界上的每一件人类神器、每一件实物,甚至每一个人都可以振振有词地连接到互联网上。所有这些东西都将能够被连接、读取和监控,并且数据驱动的智能将被持续交付。

在传统环境中,数据沿着熟悉的路线传输。专有数据和信息存储在常规数据库中,并在报告中进行分析;然后上升到管理链。

这些熟悉的数据和信息流路线将根据物联网的新范式而改变。在物联网中,来自外部世界的数据(来自设备的传感器和执行器)将成为重要的信息源,这将促进对真正互联世界的真实分析。

新兴的 PIG 设计模式可能会解决即将到来的来自物联网的数据洪流。这些模式可能需要定期集成高速流数据,并使用 Pig 来执行流分析。与实施风暴中的 PIG 和 Tez 中的 PIG 相关的拟议工作可能是一个很好的起点。

解决方案驱动模式的出现

随着设计模式在许多业务问题中继续被更广泛地接受,用户倾向于看到将这些模式分组到可管理的模块化可重用模式库中的好处。在这本书里,重点是根据熟悉的数据从摄入到排出的路径对模式进行分组;可能有一种新颖的分组机制,其中模式基于功能使用进行分组。从这个角度来看,更新的设计模式可能会填补本书没有提到的空白。

求解可编程性约束的模式

Pig 设计为数据驱动的过程语言,可用于小规模分析,不适合复杂的数学算法。它的支柱是站在数据管道的前面,努力理解、吸收、整合数据,让 R、Weka、Python、OpenNLP、Mahout 这样的库能够分析数据。

由于固有的复杂性,迫切需要将这些外部库与 Pig 无缝集成。一般来说,我们在将 Pig 与 R 或任何其他分析库集成时都会遇到困难。这些问题包括没有找到库中实现的所有常用算法、注册库函数、数据类型不兼容、缺少内置函数等。

更新的设计模式可能会出现,导致这些外部库和 Pig 之间的集成框架更加紧密。Pig 的可伸缩性特性,如流和 UDF,在实现这些框架时会派上用场。这些设计模式利用了库的统计分析能力和 Pig 的并行数据处理能力。

总结

在本章中,我们将探索一些高级模式,这些模式涉及使用 Pig 来使用各种模式分析非结构化文本数据。

我们首先了解文本数据聚类背后的背景和动机;然后,我们简要检查了几种技术,接着是一个用例,Pig 代码详细解释了这个用例。同样,通过一个包含大数据和医学的文本示例,我们理解了主题模型对于理解文本文档潜在上下文的相关性。我们已经探索了 Pig 如何与 Python 的NLTK库集成来执行自然语言处理,从而将文本语料库分解成句子并识别命名实体。这些实体最终被用于索引和信息检索。在最后一种模式中,我们考虑一个信用数据集来说明使用与 Pig 集成的 Mahout 进行分类或预测分析的过程。

未来趋势结合 Pig 作为处理大数据的主流编程语言的发展,确定了未来的设计模式。这一部分还将设计模式的进步性带入视野,使你能够识别和开发你从未见过的新设计模式,并与世界分享。

希望这本书能给你提供一个跳板,让你轻松使用这本书提到的设计模式。这弥合了创建复杂数据管道的理论理解和实际实现之间的差距,并将其应用于数据管理生命周期和分析的所有阶段。通过这本书,我们讲述了大数据从进入企业到最终被用于分析的过程;在整个旅程中,Pig 设计模式起到了催化剂的作用,指导我们完成数据管理生命周期和分析的下一步工作。

posted @ 2025-10-23 15:14  绝不原创的飞龙  阅读(3)  评论(0)    收藏  举报