说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

利用Hadoop Streaming处理二进制格式文件

HTML文档下载 WORD文档下载 PDF文档下载
Hadoop Streaming是Hadoop提供的多语言编程工具,用户可以使用自己擅长的编程语言(比如python、php或C#等)编写Mapper和Reducer处理文本数据。Hadoop Streaming自带了一些配置参数可友好地支持多字段文本数据的处理

编者按:Streaming是Hadoop的一个工具,用来创建和运行一类特殊的Map/Reduce作业。Streaming使用“标准输入”和“标准输出”与我们编写的Map和Reduce进行数据的交换。由此可知,任何能够使用“标准输入”和“标准输出”的编程语言都可以用来编写MapReduce程序。今天给大家分享一篇来自董西成的博文“利用Hadoop Streaming处理二进制格式文件”,文中介绍了如何使用Streaming处理二进制格式的文件。


CSDN推荐:欢迎免费订阅《Hadoop与大数据周刊》获取更多Hadoop技术文献、大数据技术分析、企业实战经验,生态圈发展趋势。


Hadoop Streaming是Hadoop提供的多语言编程工具,用户可以使用自己擅长的编程语言(比如python、php或C#等)编写Mapper和Reducer处理文本数据。Hadoop Streaming自带了一些配置参数可友好地支持多字段文本数据的处理,参与Hadoop Streaming介绍和编程,可参考我的这篇文章:“Hadoop Streaming编程实例”。然而,随着Hadoop应用越来越广泛,用户希望Hadoop Streaming不局限在处理文本数据上,而是具备更加强大的功能,包括能够处理二进制数据;能够支持多语言编写Combiner等组件。随着Hadoop 2.x的发布,这些功能已经基本上得到了完整的实现,本文将介绍如何使用Hadoop Streaming处理二进制格式的文件,包括SequenceFile,HFile等。

注:本文用到的程序实例可在百度云:hadoop-streaming-binary-examples 下载。

在详细介绍操作步骤之前,先介绍本文给出的实例。假设有这样的SequenceFile,它保存了手机通讯录信息,其中,key是好友名,value是描述该好友的一个结构体或者对象,为此,本文使用了google开源的protocol buffer这一序列化/反序列化框架,protocol buffer结构体定义如下:

option java_package = "";
option java_outer_classname="PersonInfo";
message Person {
  optional string name = 1;
  optional int32 age = 2;
  optional int64 phone = 3;
  optional string address = 4;
}

SequenceFile文件中的value便是保存的Person对象序列化后的字符串,这是典型的二进制数据,不能像文本数据那样可通过换行符解析出每条记录,因为二进制数据的每条记录中可能包含任意字符,包括换行符。

一旦有了这样的SequenceFile之后,我们将使用Hadoop Streaming编写这样的MapReduce程序:这个MapReduce程序只有Map Task,任务是解析出文件中的每条好友记录,并以name \t age,phone,address的文本格式保存到HDFS上。

1. 准备数据

首先,我们需要准备上面介绍的SequenceFile数据,生成数据的核心代码如下:

final SequenceFile.Writer out =
        SequenceFile.createWriter(fs, getConf(), new Path(args[0]),
                Text.class, BytesWritable.class);
Text nameWrapper = new Text();
BytesWritable personWrapper = new BytesWritable();
System.out.println("Generating " + num + " Records......");
for(int i = 0; i < num; i++) {
  genOnePerson(nameWrapper, personWrapper);
  System.out.println("Generating " + i + " Records," + nameWrapper.toString() + "......");
  out.append(nameWrapper, personWrapper);
}
out.close();

当然,为了验证我们产生的数据是否正确,需要编写一个解析程序,核心代码如下:

Reader reader = new Reader(fs, new Path(args[0]), getConf());
Text key = new Text();
BytesWritable value = new BytesWritable();
while(reader.next(key, value)) {
  System.out.println("key:" + key.toString());
  value.setCapacity(value.getSize()); // Very important!!! Very Tricky!!!
  PersonInfo.Person person = PersonInfo.Person.parseFrom(value.getBytes());
  System.out.println("age:" + person.getAge()
          + ",address:" + person.getAddress()
          +",phone:" + person.getPhone());
}
reader.close();

需要注意的,Value保存类型为BytesWritable,使用这个类型非常容易犯错误。当你把一堆byte[]数据保存到BytesWritable后,通过BytesWritable.getBytes()再读到的数据并不一定是原数据,可能变长了很多,这是因为BytesWritable采用了自动内存增长算法,你保存的数据长度为size时,它可能将数据保存到了长度为capacity(capacity>size)的buffer中,这时候,你通过BytesWritable.getBytes()得到的数据最后一些字符是多余的,如果里面保存的是protocol buffer序列化后的字符串,则无法反序列化,这时候可以使用BytesWritable.setCapacity (value.getSize())将后面多余空间剔除掉。

2. 使用Hadoop Streaming编写C++程序

为了说明Hadoop Streaming如何处理二进制格式数据,本文仅仅以C++语言为例进行说明,其他语言的设计方法类似。

先简单说一下原理。当输入数据是二进制格式时,Hadoop Streaming会对输入key和value进行编码后,通过标准输入传递给你的Hadoop Streaming程序,目前提供了两种编码格式,分别是rawtypes和  typedbytes,你可以设计你想采用的格式,这两种编码规则如下(具体在文章“Hadoop Streaming高级编程”中已经介绍了):

rawbytes:key和value均用【4个字节的长度+原始字节】表示

typedbytes:key和value均用【1字节类型+4字节长度+原始字节】表示

本文将采用第一种编码格式进行说明。采用这种编码意味着你不能想文本数据那样一次获得一行内容,而是依次获得key和value序列,其中key和value都由两部分组成,第一部分是长度(4个字节),第二部分是字节内容,比如你的key是dongxicheng,value是goodman,则传递给hadoop streaming程序的输入数据格式为11 dongxicheng 7 goodman。为此,我们编写下面的Mapper程序解析这种数据:

int main() {
 string key, value;
 while(!cin.eof()) {
  if(!FileUtil::ReadString(key, cin))
   break;
  FileUtil::ReadString(value, cin);
  Person person;
  ProtoUtil::ParseFromString(value, person);
  cout << person.name() << "\t" << person.age()
       << "," << person.address()
       << "," << person.phone() << endl;
 }
 return 0;
}

其中,辅助函数实现如下:

class ProtoUtil {
 public:
  static bool ParseFromString(const string& str, Person &person) {
   if(person.ParseFromString(str))
    return true;
   return false;
  }
};
class FileUtil {
 public:
  static bool ReadInt(unsigned int *len, istream &stream) {
   if(!stream.read((char *)len, sizeof(unsigned int)))
    return false;
   *len = bswap_32(*len);
   return true;
  }
  static bool ReadString(string &str, istream &stream) {
   unsigned int len;
   if(!ReadInt(&len, stream))
    return false;
   str.resize(len);
   if(!ReadBytes(&str[0], len, stream))
    return false;
   return true;
  }
  static bool ReadBytes(char *ptr, unsigned int len, istream &stream) {
   stream.read(ptr, sizeof(unsigned char) * len);
   if(stream.eof()) return false;
   return true;
  }
};

该程序需要注意以下几点:

(1)注意大小端编码规则,解析key和value长度时,需要对长度进行字节翻转。

(2)注意循环结束条件,仅仅靠!cin.eof()判定是不够的,仅靠这个判定会导致多输出一条重复数据。

(3)本程序只能运行在linux系统下,windows操作系统下将无法运行,因为windows下的标准输入cin并直接支持二进制数据读取,需要将其强制以二进制模式重新打开后再使用。

3. 程序测试与运行

程序写好后,第一步是编译C++程序。由于该程序需要运行在多节点的Hadoop集群上,为了避免部署或者分发动态库带来的麻烦,我们直接采用静态编译方式,这也是编写Hadoop C++程序的基本规则。为了静态编译以上MapReduce程序,安装protocol buffers时,需采用以下流程(强调第一步),

./configure –disable-shared
make –j4
make install

然后使用以下命令编译程序,生成可执行文件ProtoMapper:

g++ -o ProtoMapper ProtoMapper.cpp person.pb.cc `pkg-config –cflags –static –libs protobuf` -lpthread

在正式将程序提交到Hadoop集群之前,需要先在本地进行测试,本地测试运行脚本如下:

#!/bin/bash
HADOOP_HOME=/opt/dong/yarn-client
INPUT_PATH=/tmp/person.seq
OUTPUT_PATH=file:///tmp/output111
echo "Clearing output path: $OUTPUT_PATH"
$HADOOP_HOME/bin/hadoop fs -rmr $OUTPUT_PATH
${HADOOP_HOME}/bin/hadoop jar\
   ${HADOOP_HOME}/share/hadoop/tools/lib/hadoop-streaming-2.2.0.jar\
  -D mapred.reduce.tasks=0\
  -D stream.map.input=rawbytes\
  -files ProtoMapper\
  -jt local\
  -fs local\
  -input $INPUT_PATH\
  -output $OUTPUT_PATH\
  -inputformat SequenceFileInputFormat\
  -mapper ProtoMapper

注意以下几点:

(1)使用stream.map.input指定输入数据解析成rawbytes格式

(2) 使用-jt和-fs两个参数将程序运行模式设置为local模式

(3)使用-inputformat指定输入数据格式为SequenceFileInputFormat

(4)使用mapred.reduce.tasks将Reduce Task数目设置为0

在本地tmp/output111目录下查看测试结果是否正确,如果没问题,可改写该脚本(去掉-fs和-jt两个参数,将输入和输出目录设置成HDFS上的目录),将程序直接运行在Hadoop上。

原文链接:利用Hadoop Streaming处理二进制格式文件       (编辑/刘亚琼  审校/仲浩)

2012末日APP推荐 求生自救必备! Windows8上网利器 不卡死的IE10浏览器 为何Java程序员学习Clojure有优势? 我们是如何阅读代码的? “热水冷却”技术将主导美国国防部数据中心改造 程序员想玩转大数据:需要知晓的12种工具 2012年谷歌应用商店增长迅速 但苹果最赚钱 Apple微软Google都在竞购一家创业公司 违反新条款?苹果强行下架AppShopper 2012移动开发教程盘点:最棒的国外游戏开发站 重思JavaScript的好与坏 细数那些 NeXT 留给 OS X 的遗产 一张图让你知道大数据的生态系统 Camera360开放SDK:拍照和滤镜一行代码搞定 一周消息树:计算机将拥有五感 人类面临威胁? 通晓数学的人就可以当程序员吗? 360发布企业版4.0 可自定义软件白名单 不要总是依赖机器 MongoDB扩展彰显分片功夫 Dell与HP的OpenStack的战略:渠道对抗SLA 路况电台王雷:未来车载系统会是Android的天下 移动周报:2012移动开发工具系列盘点 谷歌不愿错失机会 Android或不再成它人独享 黑客文化:Facebook公布2012年Hackathon大赛顶级“黑客作品” 中国移动音乐开放平台正式对外开放 GitLab 4.0发布 更好地支持PostgreSQL 傻瓜式移动应用开发平台:专访摩讯创始人赵健 日本DeNA进军中国智能电视,与海信战略合作 扎克伯格不仅为Poke编码,而且还“献声” Wordament:首款支持Xbox Live成就的iPhone游戏 使用Storm实现实时大数据分析! 孙博凯:微软日益开放,Windows Azure更加拥抱开源 各位大虾:那有中文的uml,Rose书籍下载?多分! 一段递推法的程序 如何是使 file 域文本内容不能编辑? yushulei(永远)接分 请问一小段代码 请教rdo访问sql server出现的问题! 如何加锁? 关于数据类型的转换的函数? 我想问一下就是怎么整理把不同条件下的数据放在一个DBGRID的问题 NTFS格式的能否再重新格成FAT32格式? 数据库能否只用一个连接? 寻求廉价远程数据库(internet)连接方案?同时高分悬赏 image字段查询问题? ▲▲▲如何让MDI主窗口显示时向下凹陷的窗口变成平的??▲▲▲ ADOQuery增加记录问题 请教存储过程高手,在线等!急 应聘HR软件方面的实施/咨询要注意什么呢? 小弟 想做个循环滚动 帮忙看一下代码 错在那里了 yushulei(永远)接分 这语句错在哪?select a.* from (SELECT min(id) FROM user )a 怎样列出客户生日来临前的一个星期所有客户名单? 我想做监控的软件,用udp 如何使用?着急! 急需求助!! 怎么样判断一个目录、文件是否存在??? 请教如何在给定的几个数中随机选出3个数? 想参加一个jsp开发组织。那里有? 为什么下面的头文件没有 .h后缀 如何在SAS软件中导入SQL SERVER 2000的数据?谢谢 请教有经验的学长:动态网页在我自己的机器上运行没有问题,但是(急) 一个奇怪的输出问题?各位C高手看过来 如何让Edit1->Text 等于float类型的变量? 菜鸟问题,在线等 Win98下的SOAP. 哪位大侠有installshield 7.0 以上版本的,发我一个,谢谢!!! 在word中用鼠标滚动的时候,左下角的 行 页变化是怎么的出来的,有没有程序呢 请大家看过来,apache配置文件是否有错,超紧急求救! 如何让Edit1->Text 等于float类型的变量? 为何提示不能创建对象?急死我了 在对话框类中怎样向视图类发送刷新视图的消息?谢谢 急,在线等!同样的打印程序(套打),为什么在不同的操作系统下面打印的位置有差别,怎么才能做到同一打印程序在不同的打印机和不同的系 DELPHI+SQL 想要怎么学习才能快速成长 哪个前辈指点指点 请你们指教好吗 串口通信问题 一个排序的问题! JBuilder下的编辑问题 急呀!vba高手帮帮忙? 动态类型转换 关于软件测试,测试结论 大家进来说说 如何在当前目录下调出一个CHM格式的文档? 为什么动态增加的WebBrowser1.Align不能为alClient啊? 怎样通过代码实现CTRL+C和CTRL+V的功能? 有两个问题要问,很难的哟,谁来挑战一下!! 有什么有趣的小学英语题目 新概念第二册清晰英音mp3还有北师大版!高二选修7、8!的听力 单词和课文的都要! 一篇关于民风民俗的习作,我土家族的,最好写土家族滴, 在上午10时30分到11时30分之间,时针和分针何时成直角? 设全集U=R,A={x|x〈-1或x〉1},B={x|x-2≥0},判断全集A与全集B之间的关系 初学者,希望有讲解. 已知集合M={x/-1<x<2},P={X/X-a≤0}.若M∩N≠空集.则a的取值范围?初学者, 这题咋写,求指导, clot的logo有什么含义啊? 小学英语5,6年级应该侧重什么评价?形成性评价还是终结性评价? 英语翻译这是在电影 《珍爱》中,地72分12秒时说的,一个俄罗斯人,他说的英文有口音,他说的这句,It shut the bumba ros clot 小学英语课怎么上才能有趣又有效? 注册零门槛屌丝也能开公司 专家:法律土耳其买中国导弹为何一波三折“美丽中国”图片展走进科特迪瓦京津冀浙多条高速路段因大雾通行受阻今起浙江93、97号汽油每升便宜6分美售P3C首架飞机抵台 马英九称与日男子在石家庄博物馆泼人硫酸 警方称嫌工作强度大工资低 台州公交公司有车无台湾花莲昨晚发生6.7级地震 台州各上海让全班学生互扇耳光老师被解聘就业市场前三季度逆势走稳 未来总量存Lady驾车 请从容自信地开恋上“微”旅行 在另一个城市过周末游客丢了十余万元财物 民警赶赴西安帮你的黄金 工行来回购以精神文明建设为动力 推进医院又好又小伙子快快来 姑娘们别害羞拉网式清除野广告5月底前见成效上千蜜蜂“路过”收费站 司机不敢开窗轿车自燃 半小时烧成铁架子《啸雷脱口秀》演出内容提前曝光市民赞摄影作品 “真实生动美得很”耀世红浊圣武仙魔录综漫之成神之路剑怒蟒之龙皇震神天炼平凡弱者英雄无敌之中国道无限宇宙世纪符文武者的冒险世界我家的太阳花新加坡环球影城旅游克拉码头旅游一线潮旅游东圳水库旅游长安区博物馆旅游西冲情人岛旅游花鸟灯塔旅游南湾海滨浴场旅游花鸟岛旅游方特欢乐世界蓝水星旅游瓜皮岛旅游
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘