chapter4MapReduceandDesignPatternsWord文件下载.docx

上传人:b****6 文档编号:16616463 上传时间:2022-11-24 格式:DOCX 页数:29 大小:320.72KB
下载 相关 举报
chapter4MapReduceandDesignPatternsWord文件下载.docx_第1页
第1页 / 共29页
chapter4MapReduceandDesignPatternsWord文件下载.docx_第2页
第2页 / 共29页
chapter4MapReduceandDesignPatternsWord文件下载.docx_第3页
第3页 / 共29页
chapter4MapReduceandDesignPatternsWord文件下载.docx_第4页
第4页 / 共29页
chapter4MapReduceandDesignPatternsWord文件下载.docx_第5页
第5页 / 共29页
点击查看更多>>
下载资源
资源描述

chapter4MapReduceandDesignPatternsWord文件下载.docx

《chapter4MapReduceandDesignPatternsWord文件下载.docx》由会员分享,可在线阅读,更多相关《chapter4MapReduceandDesignPatternsWord文件下载.docx(29页珍藏版)》请在冰豆网上搜索。

chapter4MapReduceandDesignPatternsWord文件下载.docx

这使得想分析个别发帖时变得更复杂。

设想用发帖的长度跟评论的长度相关联,这需要首先做一次代价较高的join操作,然后抽取有用的数据。

如果换成根据发帖分组数据,使发帖跟相关联的评论,编辑,修改数据紧挨着(例如反规范化表数据),这样分析起来会更容易和直观。

这种情况下保存结构化数据完全达不到目的。

不幸的是,数据不总是分组在一块。

当某人回复了stackOverflow的某个问题,hadoop不能够把这条记录立刻插到层次数据中。

因此,用MapReduce创建非结构化记录只适用于周期性的批处理形式的业务逻辑。

另一种能平稳更新数据的方式是用Hbase。

Hbase能存储半结构化和层次样式的数据。

MongoDB也能很好的处理这种数据的排序。

Applicability

这种模式适合的场景:

你的数据靠很多外键相联系

你的数据是结构化的基于行的

Structure

图4-1展示了这种模式的结构,每部分组件描述如下:

如果你想合并多个数据源成为一个有层次的数据结构,hadoop中有个类:

org.apache.hadoop.mapreduce.lib.input.MultipleInputs很适合使用(貌似很老的包)。

Mutipleinputs允许你对不同的input使用不同的inputpath和不同的mapper。

Driver里完成配置。

如果只有一个来源,则不需要这一步。

mapper加载数据并解析成紧凑的格式从而使reducer更容易。

输出key应该是你想要标识的每一条层次记录的根。

例如,在stackOverflow例子里,根是发帖id。

也需要给没片数据标注来源信息。

也需要标识输出记录是发帖还是评论。

这样的话,就能简单连接这些标签并输出值。

通常,这里用combiner起不了多大作用。

可以用相同的key对条目分组,一起发送,但这样没有压缩所起到的好处,因为要做的知识连接字符串,所以输出大小不变。

reducer按key从不同的源接收数据。

所有的数据对指定的分组,每组都会产生一个迭代器,剩下你需要做的就是用数据条目构建有层次的数据结构。

使用xml或json,可以构建一个简单的对象并输出。

这部分的例子使用xml,提供了几个方便的方法处理结构化数据。

如果使用其他格式,例如自定义的格式,也要使用合适的构建对象的方法和序列化方法。

Consequences

输出是一种有层次的形式,根据指定的key分组的。

注意很多格式例如xmljson都有某种顶层根元素包在所有记录外面。

如果想让文档从根到底部都有良好的格式,也比较容易在特定的处理阶段加上头部或尾部。

Figure4-1.Thestructureofthestructuredtohierarchicalpattern

Knownuses

Pre-joiningdata

数据是杂乱的结构化数据集,为了分析,也很容易把数据组合成更复杂的对象。

通过这样,你设置好数据来充分利用分析nosql模型的优势。

PreparingdataforHBaseorMongoDB

Hbase是很自然的存储这类数据的方式。

所以可以用这种方法把数据搞到一起,作为加载到hbase或mongoDB的准备工作。

创建hbase表,然后通过MapReduce执行大量导入是很高效的。

另一种方案是分几次导入,可能效率较低。

Resemblances

Sql

RDB中这样的事情是很少见的,因为这样存储用sql分析不是很方便。

然而,这种方式可以解决RDBMS中的类似问题,比如做join然后在结果上做分析。

Pig

Pig对层次数据有适当的支持,可以取到层次的包和元组,然后就能容易的展现出层次结构和列出单条记录的对象。

Pig中的cogroup方法会保存原始结构做大量的合并数据的操作。

然而,使用这个关键词在复杂记录上做任何种类的实时分析都会有挑战性。

所以,自定义个方法是好的选择。

基本做法是使用pig创建并分组记录,然后用udf去分析数据。

data_a=LOAD'

/data/comments/'

ASPigStorage('

|'

);

data_b=LOAD'

/data/posts/'

'

grouped=COGROUPdata_aBY$2,data_bBY$1;

analyzed=FOREACHgroupedGENERATEudfs.analyze(group,$1,$2);

Performanceanalysis

使用这种模式时有两个性能关注点。

第一个,需要知道mapper发送到reducer的数据量,第二个,要清楚reducer创建的对象的内存使用情况。

因为要使用key分组的记录可以遍布在数据集的任何地方,很多数据会通过网络传输。

基于此原因,你需要注意使用适当的reducer的数量。

策略跟其它模式中的一样。

下一个主要关注的是数据的热点问题的可能性,它可以导致记录的暴增。

对大的数据集,一个特殊的输出记录会有很多数据与之关联是很可能出现的情况。

设想下stackOverflow上发了一个帖子,有一百万的评论。

这种情况相对少见,但不是不可能的。

如果你在创建某种xml对象,所有的评论某一时刻在输出之前都会存储在内存里。

这可能造成jvm的OOM,这种情况应该避免。

另一个热点问题是reducer处理的数据的倾斜问题。

这跟普通MapReducejob可能遇到的问题相似。

很多时候,倾斜问题可以忽略,如果倾斜很严重就写个自定义的partitioner使数据分发得更均匀。

StructuredtoHierarchicalExamples

Post/commentbuildingonStackOverflow

这个例子里,我们将拿到stackOverflow的发帖和评论数据并分组。

层次结构如下所示:

Posts

Post

Comment

问题:

给出用户发帖和评论数据,创建结构化的xml层次结构,将相关的评论嵌套在对应的发帖之内。

Drivercode。

我们通常不会描述驱动代码,但这个例子中会加入新的东西:

MultipleInput。

创建这个对象,把评论数据和发帖数据的路径加到指定的mapper。

这两个路径是通过命令行提供的,通过args数组获得。

publicstaticvoidmain(String[]args)throwsException{

Configurationconf=newConfiguration();

Jobjob=newJob(conf,"

PostCommentHierarchy"

job.setJarByClass(PostCommentBuildingDriver.class);

MultipleInputs.addInputPath(job,newPath(args[0]),

TextInputFormat.class,PostMapper.class);

MultipleInputs.addInputPath(job,newPath(args[1]),

TextInputFormat.class,CommentMapper.class);

job.setReducerClass(UserJoinReducer.class);

job.setOutputFormatClass(TextOutputFormat.class);

TextOutputFormat.setOutputPath(job,newPath(args[2]));

job.setOutputKeyClass(Text.class);

job.setOutputValueClass(Text.class);

System.exit(job.waitForCompletion(true)?

0:

2);

}

Mappercode。

这里有两个mapper类,分别是评论和发帖类。

两者都用发帖id作为输出key。

输出值用字符(p代表发帖,c代表评论),我们在reduce阶段就会知道数据来自哪里。

publicstaticclassPostMapperextendsMapper<

Object,Text,Text,Text>

{

privateTextoutkey=newText();

privateTextoutvalue=newText();

publicvoidmap(Objectkey,Textvalue,Contextcontext)

throwsIOException,InterruptedException{

Map<

String,String>

parsed=MRDPUtils.transformXmlToMap(value

.toString());

//TheforeignjoinkeyisthepostID

outkey.set(parsed.get("

Id"

));

//Flagthisrecordforthereducerandthenoutput

outvalue.set("

P"

+value.toString());

context.write(outkey,outvalue);

}

}

publicstaticclassCommentMapperextendsMapper<

parsed=MRDPUtils.transformXmlToMap(value.toString());

PostId"

C"

Reducercode。

Reducer创建有层次的xml对象。

所有的值被迭代,来得到发帖记录和对应的评论列表。

我们知道根据标识分别记录并加到值里。

标识在指派为帖子(对应为帖子)或加到list(对应为评论)时移除掉。

如果帖子不为空,就按帖子为父节点,评论为子节点创建xml记录。

紧随其后的是nestElements。

使用xmlapi创建xml记录,你可以在需要时尽情使用。

publicstaticclassPostCommentHierarchyReducerextends

Reducer<

Text,Text,Text,NullWritable>

privateArrayList<

String>

comments=newArrayList<

();

privateDocumentBuilderFactorydbf=DocumentBuilderFactory

.newInstance();

privateStringpost=null;

publicvoidreduce(Textkey,Iterable<

Text>

values,Contextcontext)

//Resetvariables

post=null;

comments.clear();

//Foreachinputvalue

for(Textt:

values){

//Ifthisisthepostrecord,storeit,minustheflag

if(t.charAt(0)=='

P'

){

post=t.toString().substring(1,t.toString().length())

.trim();

}else{

//Else,itisacommentrecord.Addittothelist,minus

//theflag

comments.add(t.toString()

.substring(1,t.toString().length()).trim());

}

}

//Iftherearenocomments,thecommentslistwillsimplybeempty.

//Ifpostisnotnull,combinepostwithitscomments.

if(post!

=null){

//nestthecommentsunderneaththepostelement

StringpostWithCommentChildren=nestElements(post,comments);

//writeouttheXML

context.write(newText(postWithCommentChildren),

NullWritable.get());

nestElements方法拿到帖子和评论的列表,创建一个xml字符串并输出。

使用DocumentBuilder和一些额外的帮助方法拷贝Element对象为新的,还有他们的属性。

这种拷贝发生在数据行转为帖子或评论时的重命名标签时。

最终的document被转换成了xml。

privateStringnestElements(Stringpost,List<

comments){

//CreatethenewdocumenttobuildtheXML

DocumentBuilderbldr=dbf.newDocumentBuilder();

Documentdoc=bldr.newDocument();

//Copyparentnodetodocument

ElementpostEl=getXmlElementFromString(post);

ElementtoAddPostEl=doc.createElement("

post"

//Copytheattributesoftheoriginalpostelementtothenewone

copyAttributesToElement(postEl.getAttributes(),toAddPostEl);

//Foreachcomment,copyittothe"

node

for(StringcommentXml:

ElementcommentEl=getXmlElementFromString(commentXml);

ElementtoAddCommentEl=doc.createElement("

comments"

//Copytheattributesoftheoriginalcommentelementto

//thenewone

copyAttributesToElement(commentEl.getAttributes(),

toAddCommentEl);

//Addthecopiedcommenttothepostelement

toAddPostEl.appendChild(toAddCommentEl);

//Addthepostelementtothedocument

doc.appendChild(toAddPostEl);

//TransformthedocumentintoaStringofXMLandreturn

returntransformDocumentToString(doc);

privateElementgetXmlElementFromString(Stringxml){

//Createanewdocumentbuilder

returnbldr.parse(newInputSource(newStringReader(xml)))

.getDocumentElement();

privatevoidcopyAttributesToElement(NamedNodeMapattributes,

Elementelement){

//Foreachattribute,copyittotheelement

for(inti=0;

i<

attributes.getLength();

++i){

AttrtoCopy=(Attr)attributes.item(i);

element.setAttribute(toCopy.getName(),toCopy.getValue());

privateStringtransformDocumentToString(Documentdoc){

TransformerFactorytf=TransformerFactory.newInstance();

Transformertransformer=tf.newTransformer();

transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,

"

yes"

StringWriterwriter=newStringWriter();

transformer.transform(newDOMSource(doc),newStreamResult(writer));

//Replaceallnewlinecharacterswithanemptystringtohave

//onerecordperline.

returnwriter.getBuffer().toString().replaceAll("

\n|\r"

"

"

Question/answerbuildingonStackOverflow

本例是前面例子的后续处理,会使用前面例子的输出作为本例的输入数据。

现在,我们已经得到了帖子和跟帖子关联的评论,现在我们要关联帖子的提问和帖子的回答。

这是需要做的,因为帖子由回答帖和提问帖构成,并根据postTypeId区分。

我们将根据提问的id和回答的父id分组到一起。

使用前面例子的输出,执行自关联操作,创建问题帖,回答帖,和评论的层次结构。

首先决定记录是问题还是回答,因为这两种记录的行为不同。

对于问题,抽取它的id作为key,并标记为问题。

对于回答,抽取父id作为key,并标记为回答。

publicclassQuestionAnswerBuildingDriver{

publicstaticclassPostCommentMapperextends

Mapper<

//Parsethepost/commentXMLhierarc

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工程科技 > 兵器核科学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1