EDUCBA-Hadoop-大数据笔记-全-
EDUCBA Hadoop 大数据笔记(全)
001:传感器数据分析导论 🚀
在本节课中,我们将学习一个名为“传感器数据分析”的新项目。我们将分析来自菲律宾的传感器数据。这个项目旨在从客户提供的输入文件中,为特定国家生成有意义的信息,以支持其制定促进国家增长与发展的战略决策。


项目背景与架构概述
这是一个实际生产项目的简化版本。输入文件为JSON格式,这是一种轻量级且流行的数据交换格式,便于通过网络传输。
以下是该项目的系统架构图,展示了数据从收集到呈现的完整流程。

数据流详解
上一节我们介绍了项目背景,本节中我们来看看数据是如何在系统中流动的。
数据收集与获取:
客户团队(属于菲律宾)会进行入户调查,收集信息,并按日、周或月的频率将JSON文件上传到他们的网络门户。我们使用Java工具程序,按计划(例如每天一次)从该门户下载这些文件到本地机器。
数据加载到Hadoop:
下载到本地机器的数据需要被复制到HDFS(Hadoop分布式文件系统)中进行处理。这个过程也是自动化的。
数据处理:
数据进入HDFS后,我们将使用MapReduce进行处理。MapReduce程序包含三个主要类:Mapper、Reducer和Driver。由于输入是JSON(本质上是文本格式),我们将使用TextInputFormat逐行读取。在Mapper中,键是偏移量(LongWritable类型),值是整行文本(Text类型)。处理完成后,输出为平面文件格式。
数据存储与分析:
处理后的数据可以存储到Hive表中。在实际生产中,我们使用MapReduce处理数据,然后将结果存入Hive。虽然Pig也能达到相同目的且更简洁,但本项目团队熟悉Java,因此选择了MapReduce。


数据可视化:
存入Hive的数据可以通过SQL Server Reporting Services(SSRS)或Analysis Services(以多维数据集形式)展示给客户。这需要通过在SQL Server中配置链接服务器来连接Hive,使得报告能查询并展示Hive中的数据。
流程自动化:
从下载数据到生成报告的整个流程,是通过Oozie工作流调度工具实现自动化的。一个Oozie工作流会顺序执行以下步骤:
- 将数据从本地机器复制到HDFS。
- 在HDFS上执行MapReduce作业处理数据。
- 将处理后的数据加载到Hive表中。
- 刷新报告或数据立方体以展示最新结果。
可生成的分析用例
理解了系统架构后,我们来看看能从这些数据中提取哪些有价值的信息。数据包含年龄、教育程度、婚姻状态、性别、纳税状态、出生国、公民身份和工作周数等字段。
以下是基于这些字段可以生成的部分分析用例:
- 男女人口统计:统计国内的男性和女性数量。政府可以据此评估人口性别比例是否符合预期,并制定相应政策(如中国的计划生育补贴政策)。
- 特定女性群体关怀:找出年龄大于45岁且处于离婚或丧偶状态的女性。这部分人群可能需要社会关怀,政府可据此建立相关福利设施或提供工作机会。
- 税收审计:对比预期所得税与实际征收的所得税。这有助于政府发现未依法纳税的个人并采取行动,确保税收用于国家发展。
- 税收预测:预测下一年度的所得税收入。可以通过分析即将年满18岁并开始工作的人群数据,将其潜在税收纳入预测模型。
- 教育水平分析:计算受教育与未受教育人口的比例。政府可据此分析教育普及的障碍(如经济问题),并采取措施(如兴建学校)提升教育水平。
- 外籍人士分析:分析非菲律宾籍但在菲居住和工作的人口数量。政府可据此调整签证配额等移民政策,以保障本国公民的就业机会。
- 童工监测:识别年龄小于18岁但有收入的人群。这有助于政府依据童工法,对雇佣童工的企业或个人采取行动。
总结
本节课中我们一起学习了“传感器数据分析”项目的整体架构与目标。我们了解了数据从客户收集、通过自动化流程进入Hadoop生态系统(HDFS、MapReduce、Hive),最终通过报表工具呈现给决策者的完整链路。同时,我们也探讨了如何从原始数据中提炼出多个有助于国家发展与治理的关键分析用例。在接下来的课程中,我们将从大数据基础开始,并最终使用MapReduce等工具实际处理这些数据。


002:理解大数据与MapReduce基础
在本节课中,我们将要学习大数据的基本概念以及MapReduce编程模型的基础知识。我们将从理解大数据的定义和核心特性开始,然后逐步深入到MapReduce的工作原理,最后通过一个实际案例演示如何用MapReduce处理JSON格式的数据。
大数据基础
上一节我们介绍了项目背景和系统架构。本节中,我们来深入理解什么是大数据。
大数据不仅仅是处理海量数据。如果仅需处理大量数据,我们可以选择其他工具,如Teradata,或者通过升级硬件来实现。大数据的独特之处在于其处理数据的综合能力。
IBM给出了一个被广泛接受的定义:任何包含“4V”特征的数据都属于大数据范畴。
大数据的4V特性
以下是构成大数据的四个核心维度:
- Volume(体量):指数据的规模巨大。根据国际数据公司(IDC)的预测,到2020年,全球数据总量将达到40泽字节(ZB)。大数据技术旨在高效处理这种规模的数据。
- Velocity(速度):指数据生成和更新的速度极快。例如,数据可能每天、每小时都在快速增长。大数据框架能够通过分布式和并行处理来应对这种高速的数据流。
- Variety(多样性):指数据类型的多样化。这是大数据的一个重要优势。我们可以处理各种格式的数据,包括日志文件、视频、音频、图像、传感器数据等。在本项目中,我们处理的就是传感器数据。
- Veracity(真实性/不确定性):指数据的质量和可信度存在不确定性。数据的格式和内容可能无法预测,例如今天收到文本文件,明天可能收到图像。大数据技术能够灵活地处理这种不确定性。
大数据的应用场景
大数据技术在许多领域都有广泛应用,以下是几个典型例子:
- 推荐系统:例如,在电商网站(如eBay、Amazon)上,根据用户的历史浏览和购买记录,向其推荐相关商品。
- 搜索质量提升:利用大数据分析用户行为,优化搜索引擎的结果质量和相关性。
- 欺诈检测:在银行和金融领域,通过分析交易模式(如异常时间、频繁交易、异地交易)来识别和预防欺诈行为。
- 其他领域:电信、政府、医疗与生命科学等行业也广泛应用大数据技术。
Hadoop架构简介
理解了大数据的概念后,我们来看看实现它的一个核心框架——Hadoop的基础架构。
Hadoop主要由两个核心层构成:
- HDFS:即Hadoop分布式文件系统,是存储层。它负责将数据分布式地存储在多台机器(数据节点)上。可以将其类比为计算机的“硬盘”。
- YARN:即资源协调者,是处理层。它负责管理集群中的计算资源,并调度应用程序。可以将其类比为计算机的“大脑”和“内存”。
在HDFS中,有一个主节点(NameNode)管理文件系统元数据,多个从节点(DataNode)存储实际数据。在YARN中,有一个主节点(ResourceManager)管理集群资源,多个从节点(NodeManager)在各自机器上执行任务。
MapReduce基础
现在,我们进入数据处理的核心——MapReduce编程模型。MapReduce是Hadoop中用于并行处理大规模数据集的编程模型。
一个标准的MapReduce作业包含三个主要部分:
- Mapper(映射器):负责读取输入数据,并执行初步的业务逻辑处理。它逐行处理数据,输入和输出都是键值对(Key-Value Pair)形式。例如,在过滤数据的场景中,Mapper会检查每一行数据,只将符合条件(如属于特定地区)的数据传递给下一个阶段。
- 输入:
(Key: 行偏移量, Value: 行内容) - 处理:执行过滤、转换等逻辑。
- 输出:
(Key: 业务相关键, Value: 处理后的值)
- 输入:
- Reducer(归约器):接收来自Mapper的输出(同样是键值对),并对相同键的值进行聚合、汇总或计算,最终生成报告或结果。
- 输入:
(Key: Mapper输出的键, Value: 该键对应的值列表) - 处理:执行求和、计数、平均值等聚合操作。
- 输出:
(Key: 结果键, Value: 聚合结果)
- 输入:
- Driver(驱动器):这是作业的主类,相当于程序的入口点(main函数)。它负责配置整个MapReduce作业的参数,例如设置Mapper和Reducer类、指定输入输出路径、定义键值类型等。
实践:处理JSON格式数据
在掌握了MapReduce基础后,本节我们来看一个具体案例:如何将JSON格式的输入文件转换为逗号分隔的平面文件。
我们的目标是不依赖专门的JSON解析库,而是编写自定义代码来提取JSON中的值,并输出为简单的文本格式。
Mapper类实现
Mapper类负责读取JSON格式的每一行,并提取其中的值。
public class MyMapper extends Mapper<LongWritable, Text, Text, Text> {
@Override
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
// 1. 将Text类型的行内容转换为String
String jsonData = value.toString();
// 2. 清洗数据:移除JSON的大括号和转义字符
jsonData = jsonData.replace(“{“, “”).replace(“}“, “”).replace(“\\”, “”);
// 3. 按逗号分割,得到 “key:value” 对的数组
String[] keyValuePairs = jsonData.split(“,”);
StringBuilder finalResult = new StringBuilder();
// 4. 遍历每个 “key:value” 对
for (String pair : keyValuePairs) {
// 按冒号分割,分离键和值
String[] keyValue = pair.split(“:”);
if (keyValue.length > 1) {
// 只取“值”的部分,并添加到结果字符串
finalResult.append(keyValue[1].trim()).append(“,”);
}
}
// 5. 输出结果:键设为null,值为拼接好的字符串
context.write(new Text(“”), new Text(finalResult.toString()));
}
}
代码解释:
- 输入键是行偏移量(
LongWritable),值是整行文本(Text)。 - 通过字符串替换操作去除JSON的结构字符。
- 将每一行按逗号分割成多个
”key:value”对。 - 遍历这些对,按冒号分割后,只取“值”的部分。
- 将所有值用逗号连接起来,作为输出值。本例中不需要输出键,所以设为空文本。

Driver类配置
由于本例只是格式转换,不需要聚合操作,因此我们没有Reducer。Driver类负责配置和提交作业。


public class MyDriver {
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf, “sensor1”); // 设置作业名称
job.setJarByClass(MyDriver.class); // 设置主类
job.setMapperClass(MyMapper.class); // 设置Mapper类
// 设置输出键值类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
// 因为没有Reducer,将Reducer任务数设为0
job.setNumReduceTasks(0);
// 设置输入和输出路径(从命令行参数获取)
FileInputFormat.addInputPath(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
// 提交作业并等待完成
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}


作业执行步骤
- 编译与打包:将Java代码编译并打包成JAR文件(例如
sensor1.jar)。 - 上传至Hadoop集群:使用工具(如WinSCP)将JAR文件上传到Hadoop主节点。
- 启动Hadoop服务:确保HDFS和YARN的相关服务(NameNode, DataNode, ResourceManager, NodeManager)都已启动。
start-dfs.sh start-yarn.sh - 执行MapReduce作业:使用
hadoop jar命令提交作业。hadoop jar sensor1.jar /input/sensor_data.json /output/demo2/input/sensor_data.json:HDFS上的输入文件路径。/output/demo2:HDFS上的输出目录路径。
- 查看结果:作业完成后,可以查看输出目录中的结果文件,内容已是逗号分隔的纯文本格式。

总结

本节课中我们一起学习了大数据的基础概念和MapReduce编程模型。我们首先了解了大数据的“4V”特性(体量、速度、多样性、真实性)及其应用场景。然后,我们探讨了Hadoop的两层核心架构:HDFS(存储)和YARN(资源管理)。接着,我们深入学习了MapReduce的工作原理,包括Mapper、Reducer和Driver三个组件的职责。最后,我们通过一个实践案例,演示了如何使用MapReduce将复杂的JSON格式数据转换为易于后续处理的平面文本文件,并完成了从代码编写到集群执行的完整流程。这为后续更复杂的数据处理任务奠定了坚实的基础。
003:MapReduce实战案例
在本节课中,我们将学习如何使用Hadoop MapReduce框架处理真实数据,并生成有价值的分析结果。我们将基于一个菲律宾人口普查数据集,完成七个具体的分析用例,从计算男女比例到识别潜在的童工问题。通过实践,你将掌握如何编写MapReduce程序来解决实际问题。
概述
上一节我们完成了数据格式的转换,将JSON文件转换为了纯文本格式。本节中,我们将基于这个纯文本文件,编写并执行一系列MapReduce程序,以提取关键的人口统计信息。每个用例都将对应一个独立的MapReduce作业。
用例一:计算男女比例
首先,我们来处理第一个用例:计算菲律宾的男女人口比例。我们的数据属于菲律宾,因此可以统计该国的男女人口数量。
以下是实现此功能的MapReduce程序核心逻辑:



Mapper类 负责读取每一行数据,提取“性别”字段,并将其作为键输出,值为1。这样,所有“男性”记录会聚合在一起,所有“女性”记录也会聚合在一起。
public class GenderMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
private final static IntWritable one = new IntWritable(1);
private Text gender = new Text();
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String line = value.toString();
String[] fields = line.split(",");
// 假设性别字段在索引3的位置
String gen = fields[3].trim();
gender.set(gen);
context.write(gender, one);
}
}
Reducer类 接收来自Mapper的键值对(如 male, [1,1,1...]),并对相同键的所有值进行求和,得到该性别的总人数。




public class GenderReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
private IntWritable result = new IntWritable();
public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
int sum = 0;
for (IntWritable val : values) {
sum += val.get();
}
result.set(sum);
context.write(key, result);
}
}

程序执行后,我们得到了输出结果:女性人数为1061,男性人数为939。政府可以根据这个男女比例数据来制定国家发展战略。
用例二:统计45岁以上且离异/丧偶的女性人数

接下来,我们处理第二个用例:统计年龄超过45岁且婚姻状况为“离异”或“丧偶”的女性人数。这个信息有助于政府为这类弱势群体提供支持,例如开设相关组织或非政府机构。



以下是实现此功能的MapReduce程序过滤逻辑:
在Mapper中,我们需要应用多个过滤条件。首先检查性别是否为女性,然后检查年龄是否大于45,最后检查婚姻状态是否为“widowed”或“divorced”。

public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String line = value.toString();
String[] fields = line.split(",");
String gender = fields[3].trim();
String ageStr = fields[0].trim();
String maritalStatus = fields[2].trim().toLowerCase();
if ("female".equals(gender)) {
try {
int age = Integer.parseInt(ageStr);
if (age > 45 && ("widowed".equals(maritalStatus) || "divorced".equals(maritalStatus))) {
context.write(new Text("qualifying_female"), one);
}
} catch (NumberFormatException e) {
// 处理年龄字段非数字的情况
}
}
}
注意:在将字符串年龄转换为整数时,我们使用了trim()方法去除可能存在的空格,避免了NumberFormatException异常。


程序运行后,输出结果为100。这意味着有100名女性符合条件,政府可以据此采取相应措施。

用例三:计算总收入
第三个用例是计算数据集中所有人的总收入。政府可以用这个数据,根据本国的税收规则计算预期所得税,并与实际税收进行对比。


在这个用例中,我们只需要关注“收入”字段。由于总收入可能很大,我们使用LongWritable类型来存储。

Mapper类 提取收入字段,并将其作为值输出。键可以设为空或一个固定标签。

public class IncomeMapper extends Mapper<LongWritable, Text, Text, LongWritable> {
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String line = value.toString();
String[] fields = line.split(",");
// 假设收入字段在索引5的位置
String incomeStr = fields[5].trim();
try {
long income = Long.parseLong(incomeStr);
context.write(new Text("total_income"), new LongWritable(income));
} catch (NumberFormatException e) {
// 处理异常
}
}
}
Reducer类 将所有收入值相加。


public class IncomeReducer extends Reducer<Text, LongWritable, Text, LongWritable> {
public void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {
long sum = 0;
for (LongWritable val : values) {
sum += val.get();
}
context.write(key, new LongWritable(sum));
}
}

最终输出总收入的数值,政府可以基于此进行税收估算。

用例四:预测下一年可能新增的纳税人
第四个用例是预测政府下一年可以期待多少新增所得税。这通过统计刚满18岁且有收入(即可能开始工作并纳税)的人数来实现。
Mapper的逻辑是筛选出年龄等于18岁且收入不为0的记录。
if (age == 18 && income > 0) {
context.write(new Text("new_taxpayers"), one);
}

程序输出结果为27,意味着预计有27人将在下一年成为新的纳税人。政府可以根据这个数字调整税收预期。




用例五:统计各教育水平人数

第五个用例是分析人口的教育构成。我们通过按“教育”字段分组并计数来实现。
Mapper将教育水平作为键输出。
String education = fields[1].trim();
context.write(new Text(education), one);
Reducer对每个教育水平进行计数。输出结果显示了各个教育类别的人数,例如“10th grade: 81”、“Doctorate: 15”等。政府可以据此了解国家的教育状况。
用例六:统计非菲律宾籍人口

第六个用例是统计非菲律宾籍的人口数量,这涉及“出生国”字段。政府可以借此管理签证和移民配额。
Mapper提取出生国字段作为键。


String countryOfBirth = fields[7].trim(); // 假设是第7个字段
context.write(new Text(countryOfBirth), one);
输出结果显示了许多其他国家及其对应人数,其中仅有8人来自菲律宾本土。这些数据对移民政策制定有参考价值。

用例七:识别潜在童工(18岁以下有收入者)
最后一个用例是识别可能违反童工法的案例,即年龄小于18岁但有收入记录的人。
Mapper的过滤条件为年龄小于18且收入大于0。

if (age < 18 && income > 0) {
context.write(new Text("child_labor"), one);
}
程序输出结果为535,表示有535名未成年人有收入记录。政府可以利用这些信息对雇佣童工的行为进行调查和处理。

总结

本节课中,我们一起学习了如何使用Hadoop MapReduce处理人口普查数据,并完成了七个实际分析用例。我们从计算基本的男女比例开始,逐步深入到更复杂的分析,如识别弱势群体、预测税收、分析教育背景和移民状况,以及检测潜在的违法行为。通过这些实践,我们掌握了如何将原始数据转化为对政府决策有价值的信息。在接下来的课程中,我们将使用Pig和Hive这些更高级的工具来实现相同的分析,以比较不同大数据处理技术的优劣。
004:Pig、MapReduce与Hive之间的区别



概述
在本节课中,我们将学习Pig、MapReduce和Hive这三种Hadoop生态系统中重要的数据处理工具。我们将重点探讨它们之间的核心区别,了解各自的适用场景,并初步介绍如何在Pig中处理JSON格式的数据。
回顾与引入
在上一节中,我们使用MapReduce处理了JSON输入文件,完成了七个业务场景的分析,将原始数据转化为对客户有意义的战略信息。

本节中,我们来看看如何使用Pig来实现相同的分析任务。在开始之前,首先需要理解Pig是什么,以及它与我们已经熟悉的MapReduce和即将学习的Hive有何不同。
Pig、MapReduce与Hive的核心区别
以下是这三种工具在多个维度的详细对比,了解这些差异有助于我们在实际项目中做出正确的技术选型。
1. 抽象级别
- MapReduce:属于低级别抽象。开发者需要编写详细的代码(如
if条件、case语句)来实现所有业务逻辑,没有隐藏底层细节。 - Pig:属于高级别抽象。它通过Pig Latin脚本语言操作,内部自动执行MapReduce程序,将复杂的实现细节对开发者隐藏,使得开发更简单。
- Hive:同样属于高级别抽象。它提供了一种类似SQL的查询语言(HiveQL),用户只需声明要做什么,而不必关心执行细节。

2. 数据处理范式
- MapReduce:是一种数据处理语言。它专注于如何读取、转换和输出数据。
- Pig:是一种数据流语言。开发者通过定义一系列关系(步骤,如S1, S2)来明确控制数据的流动和处理过程。
- Hive:是一种数据声明语言。用户通过编写查询语句来描述需要什么数据,由Hive引擎决定如何执行。
3. 语言类型
- MapReduce:使用编译型语言(如Java、Scala、Python)。编写完成后需要编译成JAR包才能执行。
- Pig:使用脚本语言(Pig Latin)。开发者编写脚本,在Pig Shell中直接解释执行。
- Hive:使用类SQL语言(HiveQL)。其语法与传统关系型数据库(如Oracle, MySQL)的SQL非常相似。

4. 代码量与性能
- MapReduce:需要编写大量代码。但由于开发者对代码有完全控制权,可以通过优化获得很高的性能。
- Pig:只需编写少量脚本。因为抽象层次高,开发者对底层优化控制有限,所以性能通常低于手动优化的MapReduce程序。
- Hive:也只需编写少量查询语句。性能依赖于Hive引擎的优化,通常低于MapReduce和Pig。
5. 适用场景
- MapReduce:最适合处理复杂的业务逻辑和各种格式的数据(如文本、图像、视频、Excel文档)。灵活性最高。
- Pig:在连接(Join)操作上比MapReduce更简单易用(例如,一句
JOIN语句即可),同样适合处理结构和非结构数据。 - Hive:主要用于数据分析。它将数据加载到表中,便于进行聚合、汇总和生成分析报告,适合商业智能和决策支持。



6. 支持的数据类型
- MapReduce:适合处理结构化与非结构化数据。
- Pig:适合处理结构化与非结构化数据。
- Hive:主要适合处理结构化数据。
技术选型指南
根据以上区别,我们可以得出简单的选型建议:
- 如果你精通Java等编程语言,且需要处理复杂逻辑或特殊格式数据,选择MapReduce。
- 如果你不熟悉底层编程,希望快速进行数据处理(尤其是连接操作),选择Pig。
- 如果你的主要任务是基于结构化数据进行查询、汇总和生成报表,选择Hive。
新的处理流程:使用Pig处理JSON
在MapReduce实践中,我们先将JSON文件转换为纯文本格式再处理。而在Pig方案中,我们将采用不同的方法。
我们将编写一个Pig函数(UDF) 来直接解析原始的JSON文件。这个函数的工作原理如下:
- 我们将JSON文件中的每一行(一个JSON对象)和一个指定的
key(例如“gender”)传递给该函数。 - 函数内部解析该行JSON文本,找到对应
key的value(例如“female”)并返回。 - 在Pig脚本中,我们可以调用这个函数获取所需字段,然后进行过滤、分组、计数等操作。
这种方法的好处是无需预先转换数据格式,可以直接对原始JSON进行操作。
Pig函数简介
Pig中有两种主要的用户自定义函数(UDF):
- Filter Function(过滤函数):返回布尔值(
true/false),通常用于WHERE条件中过滤数据。 - Eval Function(求值函数):返回一个字符串或其它类型的值,用于数据提取和转换。
对于我们的JSON解析需求,我们将使用Eval Function。该函数需要继承org.apache.pig.EvalFunc类,并重写exec方法。在该方法中,我们实现从传入的元组(Tuple,代表数据行)和key参数中提取对应value的逻辑。
本节总结
本节课我们一起学习了Pig、MapReduce和Hive的核心区别,包括它们的抽象级别、处理范式、语言类型、性能特点和适用场景。我们还介绍了如何使用Pig函数直接处理JSON数据的新流程,并简要了解了Pig函数的类型。


在下一节中,我们将动手实践:导出编写好的Pig函数JAR包,将其注册到Pig环境中,并开始使用Pig Latin脚本来实现第一个数据分析场景。
005:使用函数在Pig中处理用例 🐷


在本节课中,我们将学习如何在Apache Pig中使用用户自定义函数(UDF)来处理具体的业务用例。我们将通过一系列步骤,从加载数据、调用函数、过滤、分组到最终输出结果,完整地演示Pig的数据处理流程。


上一节我们介绍了Pig、MapReduce和Hive的基本概念与区别。本节中,我们将开始动手实践,在Pig中处理具体的业务场景。
环境准备与数据加载
首先,我们需要启动Pig环境并加载数据。Pig是一种数据流语言,开发者可以控制数据的处理流程。

以下是在Pig Grunt Shell中执行的初始步骤:
- 注册UDF的JAR文件:在使用自定义函数前,必须先注册包含该函数的JAR包。
REGISTER /path/to/pigJson.jar; - 加载数据文件:我们将JSON格式的输入文件加载到Pig中。这里使用
PigStorage加载器,并以星号*作为分隔符,将所有数据放入单个列中。s1 = LOAD '/json/sensor_data.txt' USING PigStorage('*'); - 查看数据结构:可以使用
DESCRIBE命令查看关系s1的模式。由于加载时未指定模式,其类型默认为bytearray。DESCRIBE s1; - 查看数据内容:使用
DUMP命令可以查看关系s1中的数据内容。DUMP s1;
使用UDF提取特定字段
现在,我们将使用预先编写好的UDF函数从JSON数据中提取特定字段的值。该函数接收两个参数:整行数据($0)和要提取的键名。

以下是提取“年龄”字段的示例:

s2 = FOREACH s1 GENERATE json.for.pig.json.for.pig($0, 'age');
DUMP s2;
执行此命令后,Pig会调用UDF,从s1的每一行数据中提取出age键对应的值,并在控制台输出所有年龄数据。



处理具体业务用例
掌握了基础操作后,我们来处理几个具体的业务场景。
用例一:计算国家内男女性别比例 👥


这个场景需要我们从数据中提取性别字段,然后按性别分组并计数。
以下是处理步骤:


- 提取性别字段:使用UDF提取
gender字段。s2_gender = FOREACH s1 GENERATE json.for.pig.json.for.pig($0, 'gender') AS gender; - 按性别分组:对
s2_gender关系中的gender字段进行分组。s3_grouped = GROUP s2_gender BY gender; - 计算每组数量:对分组后的数据计算每个性别的记录数。
s4_count = FOREACH s3_grouped GENERATE group, COUNT(s2_gender); DUMP s4_count;
执行后,我们将得到类似(male, 939)和(female, 10161)的结果,即男性和女性的数量。
用例二:筛选年龄大于45岁的离婚或丧偶女性 🧓
这个场景更复杂,需要同时提取多个字段并进行复合条件过滤。
以下是处理步骤:
- 提取多个字段:一次性提取
gender、age和marital_status字段。s2_multi = FOREACH s1 GENERATE json.for.pig.json.for.pig($0, 'gender') AS gender, json.for.pig.json.for.pig($0, 'age') AS age, json.for.pig.json.for.pig($0, 'marital_status') AS m_status; - 进行数据过滤:使用
FILTER操作筛选出性别为女性、且婚姻状态为“离婚”或“丧偶”的记录。注意,提取出的字符串可能包含空格,使用TRIM函数去除。
注意:目前过滤条件中未包含“年龄大于45岁”,因为从UDF提取的s3_filtered = FILTER s2_multi BY (TRIM(gender) == 'female') AND (TRIM(m_status) == 'divorced' OR TRIM(m_status) == 'widowed'); DUMP s3_filtered;age是字符串类型,需要额外的过滤函数将其转换为数值类型后才能进行大小比较。


- 将结果存储到HDFS:除了在控制台查看,我们还可以将结果写回HDFS。
这会在HDFS的STORE s3_filtered INTO '/json/out';/json目录下创建一个out文件夹,并将结果文件存储其中。
其他用例思路 💡
对于其他用例,处理思路是相似的:


- 预期收入与实际收入:提取
income字段,但需要编写过滤函数将字符串收入转换为数值(如double类型),然后才能进行求和(SUM)等聚合计算。 - 国家受教育与未受教育人口问题:提取
education字段,按教育水平分组(GROUP BY),然后计算每组的数量(COUNT)。这完全可以在字符串类型上操作。 - 来自特定国家的人数:提取
country_of_birth字段,过滤出特定国家(如Philippines),然后计数。这也适用于字符串过滤。 - 年龄小于18岁的人数:提取
age字段,并需要编写过滤函数将其转换为整数(int),然后才能过滤出age < 18的记录并进行计数。
核心要点:当需要对数值进行比较(如大于、小于)或算术运算(如求和、平均)时,必须通过UDF或内置函数将字符串字段转换为合适的数值类型。对于纯粹的分类、分组和字符串匹配,则可以直接使用提取出的字符串字段。


总结与下节预告
本节课中我们一起学习了如何在Pig中应用UDF处理实际用例。我们经历了完整的流程:注册JAR、加载数据、调用UDF提取字段、使用FILTER进行条件筛选、使用GROUP BY进行分组聚合,以及使用STORE将结果输出到HDFS。


我们了解到,Pig通过高级的Pig Latin脚本,将底层MapReduce的复杂性封装起来,让开发者能够更专注于数据流逻辑本身。对于更复杂的数值比较和计算,则需要借助自定义的过滤函数。
在下一节中,我们将转向Hive。我们将在Hive中直接基于相同的JSON格式数据创建表,并编写HiveQL查询语句来实现本节中所有的业务场景,进一步比较不同工具在处理同类问题时的差异。
006:在Hive中处理JSON文件的方法流程 🗂️
在本节课中,我们将学习如何使用Hive进行数据分析,特别是如何处理JSON格式的数据。我们将了解Hive的基本概念、适用场景,并开始为后续的七个具体分析用例做准备。
Hive概述
上一节我们介绍了MapReduce和Pig,本节中我们来看看Hive。Hive本质上是一个数据分析工具,而非数据处理工具。它最初由Facebook开发,后来成为Apache的一个顶级项目,因此被称为Apache Hive。
Facebook开发Hive的原因是,行业中有许多从业者不熟悉Java、Python、Scala等编程语言,但他们精通数据分析。这些人员通常具有数据库背景,非常熟悉数据库查询和性能优化。因此,Hive是为数据分析而生的工具,用户可以将数据加载到表中,然后根据业务逻辑生成各种报告、汇总数据或执行聚合操作。
Hive是一个数据分析工具,我们可以用它为客户或组织管理层生成报告。管理层可以查看这些报告并做出决策,以促进增长或改进组织、国家等各个层面的流程。具体分析的数据类别取决于数据本身的归属,可能是国家数据,也可能是组织数据。
在我们的案例中,我们正在分析菲律宾国家的数据。最初,我们获得原始文件后,扮演了数据科学家或数据分析师的小角色,生成了七个有用的分析场景。我们可以将这些场景的输出提供给该国,帮助他们更好地改进系统、做出决策,从而以更好的方式发展国家。
例如,我们执行了一个用例:“有多少人来自菲律宾?” 在这个用例中,我们提供了来自菲律宾的人数和外来人数的数据。如果该国获得这些数据,他们就可以对签证进行限制,因为所有国家都有配额。如果超过阈值,他们就可以限制签证,每年只允许一定数量的人入境。
我们通过MapReduce和Pig处理了数据并提供了输出。在最初的视频中,我们解释了在生产环境中它是如何工作的架构。这是我正在从事的一个实际项目的一小部分,用于演示。
如果你能回忆起我的第一个视频,我们讨论了最终报告:团队将数据上传到一个网络门户,我们下载该数据,在HDFS中处理,然后将数据加载到Hive表中。最后,客户如何能够看到所有这些分析的结果。
有多种渠道可以传递输出,例如我们可以每天将输出文件发送给客户,或者将输出文件共享在某个共享目录中,以便客户每天访问。但在这里,我们以报告的形式展示输出,即使用SQL Server Reporting Services (SSRS)。我们在办公室服务器上配置了SSRS:下载了Hive ODBC驱动程序,通过DNS域服务器安装并配置,然后在SQL Server中创建了一个链接服务器。因为SSRS可以轻松通过SQL Server连接,而SQL Server通过一个称为链接服务器的ODBC连接与Hive相连。我们在SQL Server中编写Hive查询,但这些查询在我们的Hive服务器上执行,然后数据返回到SQL Server,我们再将其展示在报告中。
采用这种方法,客户无需访问目录或查看邮件。他们可以轻松地从手机、笔记本电脑或办公室机器等任何地方登录,在我们提供的URL上查看报告。我们每天都会收到这些文件,输出每天都会变化。例如,今天该国的数据可能是60%男性和40%女性,处理完明天的数据后,计数可能会变为58%男性和52%女性。客户可以根据他们查看输出的时间和批次,在其终端执行相应的操作。
Hive简介与工作原理
现在,从本节开始,我们将在Hive中实现那七个用例。在继续之前,我们想进一步讨论Hive。
Hive看起来像SQL(结构化查询语言),它被称为HQL(Hive查询语言)。Hive查询语言基本上是一种语言,我们可以编写与SQL类似、几乎相同的查询。Hive基本上是基于MySQL数据库的,因此大多数语法与MySQL非常相似。Hive是构建在Hadoop(即HDFS)之上的工具。
当我们将数据加载到表中时,数据不会移动到别处。数据仍然驻留在HDFS中,但是以目录的形式存在。目录名称就是我们创建的对象,例如我们创建一个名为temp的表,它会在Hive仓库中创建一个名为temp的目录,然后将我们加载到temp表中的数据文件存储到该目录中。它将输入文件保存在temp目录中,每当我们查询时,它会访问该目录、读取文件并显示数据。
在内部,它再次使用了MapReduce。但正如我们在看区别时所看到的,它同样是一种高级抽象,与Pig类似。复杂性对用户或开发者是隐藏的,因此我们可以轻松编写查询,但在内部,它执行MapReduce程序,并以表格形式向我们显示输出,就像在任何RDBMS中看到输出一样。它用于数据分析,而非数据处理。借助这个工具,我们可以通过编写智能查询,轻松根据业务需求生成报告。它非常易于使用,并且几乎基于与MySQL相同的概念。
最初由Facebook为其不熟悉Java、主要属于SQL背景的开发人员开发,后来Apache软件基金会接管并进一步将其发展为开源项目,从此被称为Apache Hive。那么,Hive之父是谁?是Facebook,但现在由Apache接管。
为什么需要Hive?
每个人都希望增加业务并产生更多收入。他们通过深入分析公司数据并做出重要的战略决策来实现这一目标,以促进公司增长。行业如何运作?他们启动新的流程、新的政策。他们如何做出所有这些决策,如何在公司中发起所有这些新事物?因为他们正在分析旧数据、旧记录、公司的所有数据,然后据此做出一些决策。
在Hive之前,我们是如何做的?在Hive之前,组织仍然通过使用任何RDBMS(如SQL Server、Oracle等)或任何ETL工具来运行和分析数据。ETL即提取、转换、加载。例如Informatica、SQL Server集成服务、Cognos等,市场上有许多工具。
最初,自动化使用ETL工具或任何RDBMS来处理和分析数据,但这对他们来说是一种痛苦,因为RDBMS和ETL工具只能在一定程度上轻松处理数据量。如果你们中有人在RDBMS领域工作,可以轻松理解:如果我们处理数百万条记录,没问题。但它会不断增加。我们都知道,大数据基本上取决于四个V:Volume(数据量)、Velocity(速度)。Volume指数据的当前大小,Velocity指数据持续增长的速度。
假设今天我处理100GB数据,但明天将是110GB,后天将是120GB,它会持续增加。那么有一天,这对我们来说将是一个痛苦,我们会遇到很多问题,比如性能下降、查询变慢、报告变慢等等。这就是问题所在。
早期,我们的组织使用SQL Server、Oracle或任何RDBMS或ETL工具,但这很痛苦,因为所有这些工具只能处理相对一定范围的数据量。而现在,我们的组织正在处理巨大的数据量、高速度、多样化的数据,并且这些数据日益增长。我希望你理解了。如果我们必须处理PB级或GB级的数据,那么我认为我们应该选择Hive作为最佳工具。
Hive的特性与限制
以下是Hive的特性,但基本上这些是我们不应使用Hive的场景:
- Hive不是关系型数据库,它用于数据分析。
- 如果你想在Hive中存储任何事务性数据(即数据被插入、更新,我们每天对数据执行数据操作语言DML操作),那么Hive不适合。因为我们不能在Hive中执行记录级别的更新、插入或删除操作。
- Hive是一个大数据工具,而大数据基于“一次写入,多次读取”的范式。这不是一个哲学,而是大数据的编程范式。
- Hive并非为实时处理数据而设计。
- Hive不支持实时查询和行级更新。
正如我所说,我们不应在Hive中执行记录级别的更新、插入或删除。Hive是为批处理而构建的。但我从用户那里听说,在Hive的最新版本中我们可以做到这一点。不过我不确定,因为我到目前为止从未使用过。因为我们将Hive用于数据分析,而非处理。我不确定我们是否可以在Hive中执行记录级别更新。但我从一些人那里听说,在Hive的最新版本中有传言说我们可以做到,需要设置一些属性和权限。但我没有尝试过。就我所知,Hive并非用于记录级别更新。
Hive的适用特性
基本上,我们应在以下特性场景中使用Hive:
- 它将数据以分布式方式存储在Hadoop分布式文件系统(HDFS)中,并且仅在Hive元存储中存储模式。
- 它专为OLAP(联机分析处理)而设计。
- 它提供了一种类似SQL的语言,称为HQL(Hive查询语言)。
- 它熟悉、快速、可扩展且可扩展。如果任何人曾使用过任何数据库,他们可以轻松地在Hive上工作。理解或使用它并不非常困难或复杂。
以下是一些与SQL相似的语法:
- 获取信息:
SELECT column_name FROM table - 所有值:使用
* - 某些值:需要在查询中提供列名或过滤条件。
- 多个条件:可以使用
AND子句。 - 选择特定列:将其放入查询中。
- 唯一记录:使用
DISTINCT。 - 排序:使用
ORDER BY,升序或降序。 - 函数:行数
COUNT,最大值MAX,最小值MIN等。
这些操作与MySQL相同。使用数据库:USE database,显示数据库:SHOW DATABASES,显示表:SHOW TABLES,描述表:DESCRIBE table,删除数据库:DROP DATABASE等等。正如我所说,Hive基本上基于MySQL,因此大多数语法与MySQL相同。
开始Hive实践
现在我们已经理解了什么是Hive,我认为我们已经准备好开始使用Hive了。现在,你知道,我们可以开始使用Hive了。
你可以看到我的Cloudera机器正在运行。这里你可以看到一个名为hive-metastore的文件夹。这是安装Hive时需要创建的文件夹。我需要将这个文件夹路径设置到hive-site.xml文件中。因为这将是我在创建元存储时使用的位置,它将在这里维护所有表的模式等信息。


如果我们进入里面,可以看到metastore_db,它是锁定的。在数据库内部,在这个存储库内部,Hive基本上维护着对象的模式。
我的Cloudera机器正在运行。我已经将这台机器连接到了我的VirtualBox。现在我们需要处理这些场景,即那七个有用的用例。


首先,我们将创建一个表。我会告诉你如何创建数据库,然后创建表。然后在该表中,我们将加载数据。然后,可能在此基础上,处理这所有七个用例。这样,在我的下一个视频中,你就可以处理这七个场景了。
这里有两个要点。我们正在处理JSON文件。有两种方法可以执行操作、处理数据:
- 我们可以编写UDF(用户定义函数),就像我们在Pig中编写的那样。在Hive中,我们也可以编写UDF,称为Hive用户定义函数。
- 另一种方式是,Hive提供了一些函数,我们可以直接使用这些函数来访问JSON对象。
在这里,我们将使用Hive为数据处理提供的方法和函数,而不是创建UDF(因为UDF我们已经在Pig中见过了)。首先,我创建数据库,然后创建表并加载数据,接着我们将处理那七个用例。

本节课中我们一起学习了Hive的基本概念、其在大数据生态系统中的角色(数据分析而非处理)、以及它基于“一次写入,多次读取”范式的特性。我们了解了Hive的适用场景与限制,并对比了其与传统RDBMS/ETL工具在处理海量、高速、多样化数据时的优势。最后,我们为下一节的实际操作做好了准备,明确了将通过Hive内置函数(而非UDF)来处理JSON数据,并完成七个分析用例。
007:基于Hive的JSON用例实践 📊

在本节课中,我们将学习如何在Hive中处理JSON格式的数据。我们将通过一系列实际用例,演示如何使用Hive的内置函数来解析JSON数据、执行查询并提取有价值的信息。课程内容将涵盖从创建数据库、加载数据到执行复杂分析查询的完整流程。
概述
我们将使用一个包含人口统计信息的JSON文件作为示例数据。目标是利用Hive的get_json_object函数,从JSON字符串中提取特定字段,并执行数据分析,例如计算性别比例、筛选特定年龄段的人群等。
环境准备与数据加载
首先,我们需要启动Hive并准备好数据环境。确保Hadoop集群运行正常,并且数据文件已上传到HDFS的指定目录。
上一节我们介绍了课程目标,本节中我们来看看如何准备环境和加载数据。
启动Hive并创建数据库
启动Hive后,我们首先创建一个新的数据库来存放我们的数据表。


CREATE DATABASE demo;

创建完成后,切换到新创建的数据库。
USE demo;


创建表结构
为了加载JSON数据,我们需要创建一个表。由于我们将整个JSON对象作为一个字符串字段加载,因此表结构非常简单。


CREATE TABLE json_data (
jdata STRING
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ‘*‘
STORED AS TEXTFILE;
这里,FIELDS TERMINATED BY ‘*‘ 指定了字段分隔符。我们使用一个在数据中不存在的字符(如星号),以确保整行JSON数据被加载到单个字符串列jdata中。
加载数据到表中
数据文件Sensor_data.txt已上传至HDFS路径/user/cloudera/input/。现在,我们将数据加载到刚创建的表中。
LOAD DATA INPATH ‘/user/cloudera/input/Sensor_data.txt‘ INTO TABLE json_data;


加载完成后,可以执行一个简单的查询来验证数据是否已成功加载。
SELECT * FROM json_data LIMIT 1;
使用Hive解析JSON数据




Hive提供了get_json_object函数,用于从JSON字符串中提取指定键的值。其基本语法如下:
get_json_object(json_string, ‘$.key‘)
json_string:包含JSON数据的字符串列。‘$.key‘:需要提取的JSON键的路径,注意键名需与数据中的大小写保持一致。
用例一:计算男女人数比例 👥


第一个用例是计算数据集中男性和女性的数量比例。
以下是执行此分析的步骤:
- 使用
get_json_object函数从jdata列中提取gender字段。 - 使用
GROUP BY对性别进行分组。 - 使用
COUNT函数统计每组的人数。
SELECT
get_json_object(jdata, ‘$.gender‘) AS gender,
COUNT(*) AS count
FROM json_data
GROUP BY get_json_object(jdata, ‘$.gender‘);
执行该查询后,我们将得到男性和女性各自的数量。


用例二:筛选年龄大于45岁且婚姻状况为离婚的女性 👩
第二个用例是找出所有年龄大于45岁且婚姻状况为“离婚”的女性记录。

以下是执行此分析的步骤:
- 从
jdata列中提取gender、age和marital_status字段。 - 在
WHERE子句中设置过滤条件:性别为女性、年龄大于45、婚姻状况为离婚。
SELECT
get_json_object(jdata, ‘$.gender‘) AS gender,
get_json_object(jdata, ‘$.age‘) AS age,
get_json_object(jdata, ‘$.marital_status‘) AS marital_status
FROM json_data
WHERE get_json_object(jdata, ‘$.gender‘) = ‘Female‘
AND CAST(get_json_object(jdata, ‘$.age‘) AS INT) > 45
AND get_json_object(jdata, ‘$.marital_status‘) = ‘Divorced‘;
注意:由于提取的年龄是字符串,在比较前需要使用CAST函数将其转换为整数类型。
其他用例示例
我们可以使用相同的模式处理更多分析需求。
以下是其他几个用例的查询示例:
-
计算总收入:对所有人的
income字段进行求和。SELECT SUM(CAST(get_json_object(jdata, ‘$.income‘) AS DOUBLE)) AS total_income FROM json_data; -
统计各教育水平人数:按
education字段分组并计数。SELECT get_json_object(jdata, ‘$.education‘) AS education, COUNT(*) AS count FROM json_data GROUP BY get_json_object(jdata, ‘$.education‘); -
统计非菲律宾籍人数:筛选
country_of_birth不等于‘Philippines‘的记录并计数。SELECT COUNT(*) AS non_philippines_count FROM json_data WHERE get_json_object(jdata, ‘$.country_of_birth‘) != ‘Philippines‘; -
查找有收入的未成年人:找出年龄小于18岁但收入大于0的记录。
SELECT COUNT(*) AS underage_with_income FROM json_data WHERE CAST(get_json_object(jdata, ‘$.age‘) AS INT) < 18 AND CAST(get_json_object(jdata, ‘$.income‘) AS DOUBLE) > 0;
总结
本节课中我们一起学习了在Hive中处理JSON数据的完整流程。
我们首先创建了数据库和表,然后将JSON数据加载到Hive表中。核心部分是使用Hive内置的get_json_object函数来解析JSON字符串,提取出所需的字段值。通过多个实际用例,我们演示了如何利用这个函数进行数据筛选、分组聚合和统计分析,从而从原始的JSON数据中提取出有意义的业务洞察。

Hive的这种方法使得处理半结构化数据变得相对简单,无需编写复杂的MapReduce程序或UDF即可完成常见的数据查询任务。

浙公网安备 33010602011771号