热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

8.2MapReduce中的序列化(一)

任务目的了解序列化和反序列化的概念和作用理解Java的序列化和反序列化实现可以自定义对象实现MapReduce框架的序列化任务清单任务1:序列化概述任务2&#x

任务目的
  • 了解序列化和反序列化的概念和作用
  • 理解 Java 的序列化和反序列化实现
  • 可以自定义对象实现 MapReduce 框架的序列化

任务清单


  • 任务1:序列化概述
  • 任务2:Java 序列化
  • 任务3:实现 MapReduce 框架的序列化

详细任务步骤


任务1:序列化概述


  • 序列化(Serialization):是指把结构化对象(Object)转化为字节流(ByteStream)。
  • 反序列化(Deserialization):是序列化的逆过程。即把字节流转回结构化对象。

Vditor

图1

 

  **为什么需要序列化和反序列化? **

  总的来说可以归结为以下几点:

  (1)永久性保存对象,保存对象的字节序列到本地文件或者数据库中;

  (2)通过序列化以字节流的形式使对象 在网络中进行传递和接收;

  (3)通过序列化在进程间传递对象。

  Java 的序列化是一个重量级序列化框架(Serializable),一个对象被序列化后,会附带很多额外的信息(各种校 验信息、header、继承体系等),不便于在网络中高效传输;所以,Hadoop 自己开发了一套序列化机制 (Writable),精简,高效。 Hadoop 中的序列化框架已经对基本类型和 null 提供了序列化的实现了。分别是:

Java 类型Hadoop Writable 类型
byteByteWritable
shortShortWritable
intIntWritable
longLongWritable
floatFloatWritable
doubleDoubleWritable
stringText
nullNullWritable

任务2:Java 序列化

  Java 序列化的过程是与平台无关的,也就是说一个 Java 对象可以在一个平台上序列化之后传输到另外一个平台上进行反序列化。

  需要进行序列化的 Java 类必须实现一个特殊的标记接口——Serializable。只有实现了 java.io.Serializable 接口的类可以进行序列化/反序列化,其中 java.io.Serializable 接口是一个标记接口,标记接口不含有任何成员和方法,标记接口的作用是标记一组类,这些类都具有相同的特定的功能,常见的标记接口还有 Cloneable。

2.1 实现 Serializable 接口

  一个类的对象要想序列化成功,必须满足两个条件:

  (1)该类必须实现 java.io.Serializable 对象;

  (2)该类的所有属性必须是可序列化的。声明为 static 和 transient 类型的成员数据不能被序列化。因为 static 代表类的状态,transient 代表对象的临时数据。

  详细代码如下所示:

package com.hongyaa.java.serializable;import java.io.Serializable;/*** 定义一个Student类,实现 Serializable 接口*/
public class Student implements Serializable {/*** 序列化ID*/private static final long serialVersionUID = -7037627544448704690L;private int id;private String name;private int age;//该属性声明为暂时的,因此不可序列化private transient String sex;public Student() {super();}public Student(int id, String name, int age, String sex) {super();this.id = id;this.name = name;this.age = age;this.sex = sex;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}@Overridepublic String toString() {return "id=" + id + ", name=" + name + ", age=" + age + ", sex=" + sex;}
}

2.2 序列化

  那么我们如何将此类的对象序列化后保存到磁盘上呢?

  (1)创建一个 ObjectOutputStream 输出流 oos

  (2)调用此输出流 oos 的 writeObject() 方法写对象

Vditor

图2

 

  详细代码如下所示:

package com.hongyaa.java.serializable;import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;/*** 序列化Student对象* **/
public class SerializeTest {public static void main(String[] args) {Student stu = new Student(1, "cendy", 22, "female");try {// ObjectOutputStream 对象输出流,将Student对象存储到/root/software/student.ser,完成对Student对象的序列化操作FileOutputStream fos = new FileOutputStream("/root/software/student.ser");ObjectOutputStream oos = new ObjectOutputStream(fos);// 序列化一个对象,并将它发送到输出流oos.writeObject(stu);oos.close();fos.close();System.out.println("Serialized data is saved in /root/software/student.ser");} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}
}

  执行结果如下所示:

Vditor

图3

 

  显示将 Student 的一个实例对象序列化到了/root/software/student.ser文件中,我们可以进入/root/software目录下进行你验证,发现创建了student.ser文件。如下图所示:

Vditor

 

图4

 

2.3 反序列化

  我们如从文本文件中将此对象的字节序列恢复成 Student 对象呢?

  (1)创建一个 ObjectInputStream 输入流 ois

  (2)调用此输入流 ois 的 readObject() 方法读取对象

Vditor

图5

 

  详细代码如下所示:

package com.hognyaa.java.serializable;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;/*** 反序列化Student对象**/
public class DeserializeTest {public static void main(String[] args) {Student stu = null;try {FileInputStream fis = new FileInputStream("/root/software/student.ser");ObjectInputStream ois = new ObjectInputStream(fis);// 从流中取出下一个对象,并将对象反序列化// 返回值类型为Object,因此需要将它转换成合适的数据类型,这里转换成Student类型stu = (Student) ois.readObject();ois.close();fis.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (ClassNotFoundException e) {System.out.println("Student class not found!!!");e.printStackTrace();} catch (IOException e) {e.printStackTrace();}System.out.println("Deserialized Student...");System.out.println(stu);}
}

  执行结果如下所示:

Vditor

图6

 

  从执行结果中可以看出,sex 的值输出为null,这是因为该属性声明为暂时的,所以它是不可序列化的数据,也没有保存在 student.ser 中。在反序列化时,该属性的值 “female” 也就没有,而是 null。

任务3:实现 MapReduce 框架的序列化

  Hadoop 自身的序列化存储格式就是实现了 Writable 接口的类,Writable 接口定义了两个方法:

  (1)使用 write(DataOutput out) 方法将数据写入到二进制数据流中

  (2)使用 readFields(DataInput in) 方法从二进制数据流中读取数据

  以流量统计项目案例为例:

  (1)数据样例

13726238888 2481 24681
13560436666 1116 954
13726230503 2481 24681
13826544101 264 0
13926435656 132 1512
13926251106 240 0
18211575961 1527 2106

  (2)字段释义

字段中文释义字段英文释义数据类型
手机号phoneString
上行流量upflowLong
下行流量downflowLong

  (3)项目需求一

  统计每一个用户(手机号)所耗费的总上行流量、总下行流量、总流量。

  期望输出数据格式:

13480253104 2494800 2494800 4989600

  下面是进行了序列化和反序列化的 FlowBean 类:

 

package com.hongyaa.sum;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.io.Writable; public class FlowBean implements Writable { private long upFlow; private long downFlow; private long sumFlow; // 序列化框架在反序列化操作创建对象实例时会调用无参构造器 public FlowBean() { super(); } // 为了对象数据的初始化方便,加入一个带参的构造函数 public FlowBean(long upFlow, long downFlow) { super(); this.upFlow = upFlow; this.downFlow = downFlow; this.sumFlow = upFlow + downFlow; } public long getUpFlow() { return upFlow; }public void setUpFlow(long upFlow) { this.upFlow = upFlow; } public long getDownFlow() { return downFlow; } public void setDownFlow(long downFlow) { this.downFlow = downFlow; } public long getSumFlow() { return sumFlow; } public void setSumFlow(long sumFlow) { this.sumFlow = sumFlow; } // 序列化方法 @Override public void write(DataOutput out) throws IOException { out.writeLong(upFlow); out.writeLong(downFlow); out.writeLong(sumFlow); } // 反序列化方法 // 注意:字段的反序列化顺序与序列化时的顺序保持一致,并且参数类型和个数也一致 @Override public void readFields(DataInput in) throws IOException { this.upFlow = in.readLong(); this.downFlow = in.readLong(); this.sumFlow = in.readLong(); } @Override public String toString() { return upFlow + "\t" + downFlow + "\t" + sumFlow; }
}

 


推荐阅读
  • HBase在金融大数据迁移中的应用与挑战
    随着最后一台设备的下线,标志着超过10PB的HBase数据迁移项目顺利完成。目前,新的集群已在新机房稳定运行超过两个月,监控数据显示,新集群的查询响应时间显著降低,系统稳定性大幅提升。此外,数据消费的波动也变得更加平滑,整体性能得到了显著优化。 ... [详细]
  • 2012年9月12日优酷土豆校园招聘笔试题目解析与备考指南
    2012年9月12日,优酷土豆校园招聘笔试题目解析与备考指南。在选择题部分,有一道题目涉及中国人的血型分布情况,具体为A型30%、B型20%、O型40%、AB型10%。若需确保在随机选取的样本中,至少有一人为B型血的概率不低于90%,则需要选取的最少人数是多少?该问题不仅考察了概率统计的基本知识,还要求考生具备一定的逻辑推理能力。 ... [详细]
  • 属性类 `Properties` 是 `Hashtable` 类的子类,用于存储键值对形式的数据。该类在 Java 中广泛应用于配置文件的读取与写入,支持字符串类型的键和值。通过 `Properties` 类,开发者可以方便地进行配置信息的管理,确保应用程序的灵活性和可维护性。此外,`Properties` 类还提供了加载和保存属性文件的方法,使其在实际开发中具有较高的实用价值。 ... [详细]
  • 类加载机制是Java虚拟机运行时的重要组成部分。本文深入解析了类加载过程的第二阶段,详细阐述了从类被加载到虚拟机内存开始,直至其从内存中卸载的整个生命周期。这一过程中,类经历了加载(Loading)、验证(Verification)等多个关键步骤。通过具体的实例和代码示例,本文探讨了每个阶段的具体操作和潜在问题,帮助读者全面理解类加载机制的内部运作。 ... [详细]
  • 本文介绍了如何利用ObjectMapper实现JSON与JavaBean之间的高效转换。ObjectMapper是Jackson库的核心组件,能够便捷地将Java对象序列化为JSON格式,并支持从JSON、XML以及文件等多种数据源反序列化为Java对象。此外,还探讨了在实际应用中如何优化转换性能,以提升系统整体效率。 ... [详细]
  • Java中不同类型的常量池(字符串常量池、Class常量池和运行时常量池)的对比与关联分析
    在研究Java虚拟机的过程中,笔者发现存在多种类型的常量池,包括字符串常量池、Class常量池和运行时常量池。通过查阅CSDN、博客园等相关资料,对这些常量池的特性、用途及其相互关系进行了详细探讨。本文将深入分析这三种常量池的差异与联系,帮助读者更好地理解Java虚拟机的内部机制。 ... [详细]
  • 在Android应用开发中,实现与MySQL数据库的连接是一项重要的技术任务。本文详细介绍了Android连接MySQL数据库的操作流程和技术要点。首先,Android平台提供了SQLiteOpenHelper类作为数据库辅助工具,用于创建或打开数据库。开发者可以通过继承并扩展该类,实现对数据库的初始化和版本管理。此外,文章还探讨了使用第三方库如Retrofit或Volley进行网络请求,以及如何通过JSON格式交换数据,确保与MySQL服务器的高效通信。 ... [详细]
  • Android中将独立SO库封装进JAR包并实现SO库的加载与调用
    在Android开发中,将独立的SO库封装进JAR包并实现其加载与调用是一个常见的需求。本文详细介绍了如何将SO库嵌入到JAR包中,并确保在外部应用调用该JAR包时能够正确加载和使用这些SO库。通过这种方式,开发者可以更方便地管理和分发包含原生代码的库文件,提高开发效率和代码复用性。文章还探讨了常见的问题及其解决方案,帮助开发者避免在实际应用中遇到的坑。 ... [详细]
  • 第二章:Kafka基础入门与核心概念解析
    本章节主要介绍了Kafka的基本概念及其核心特性。Kafka是一种分布式消息发布和订阅系统,以其卓越的性能和高吞吐量而著称。最初,Kafka被设计用于LinkedIn的活动流和运营数据处理,旨在高效地管理和传输大规模的数据流。这些数据主要包括用户活动记录、系统日志和其他实时信息。通过深入解析Kafka的设计原理和应用场景,读者将能够更好地理解其在现代大数据架构中的重要地位。 ... [详细]
  • 在前一篇文章《Hadoop》系列之“踽踽独行”(二)中,我们详细探讨了云计算的核心概念。本章将重点转向物联网技术,全面解析其基本原理、应用场景及未来发展前景。通过深入分析物联网的架构和技术栈,我们将揭示其在智能城市、工业自动化和智能家居等领域的广泛应用潜力。此外,还将讨论物联网面临的挑战,如数据安全和隐私保护等问题,并展望其在未来技术融合中的重要角色。 ... [详细]
  • 在Hive中合理配置Map和Reduce任务的数量对于优化不同场景下的性能至关重要。本文探讨了如何控制Hive任务中的Map数量,分析了当输入数据超过128MB时是否会自动拆分,以及Map数量是否越多越好的问题。通过实际案例和实验数据,本文提供了具体的配置建议,帮助用户在不同场景下实现最佳性能。 ... [详细]
  • 技术日志:深入探讨Spark Streaming与Spark SQL的融合应用
    技术日志:深入探讨Spark Streaming与Spark SQL的融合应用 ... [详细]
  • 如何提升Python处理约1GB数据集时的运行效率?
    如何提升Python处理约1GB数据集时的运行效率?本文探讨了在后端开发中使用Python处理大规模数据集的优化方法。通过分析常见的性能瓶颈,介绍了多种提高数据处理速度的技术,包括使用高效的数据结构、并行计算、内存管理和代码优化策略。此外,文章还提供了在Ubuntu环境下配置和测试这些优化方案的具体步骤,适用于从事推荐系统等领域的开发者。 ... [详细]
  • 阿里云大数据计算服务MaxCompute (原名 ODPS)
     MaxCompute是阿里EB级计算平台,经过十年磨砺,它成为阿里巴巴集团数据中台的计算核心和阿里云大数据的基础服务。去年MaxCompute做了哪些工作,这些工作背后的原因是什 ... [详细]
  • 本文整理了Java中org.apache.hadoop.mapreduce.lib.input.MultipleInputs.addInputPath()方法的一些代码 ... [详细]
author-avatar
多米音乐_34063629
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有