2020国产成人精品视频,性做久久久久久久久,亚洲国产成人久久综合一区,亚洲影院天堂中文av色

分享

hadoop單元測(cè)試方法--使用和增強(qiáng)MRUnit

 風(fēng)自向前 2011-06-22

1前言

         hadoop的mapreduce提交到集群環(huán)境中出問(wèn)題的定位是比較麻煩的,有時(shí)需要一遍遍的修改代碼和打出日志來(lái)排查一個(gè)很小的問(wèn)題,如果數(shù)據(jù)量大的話調(diào)試起來(lái)相當(dāng)耗時(shí)間。因此有必要使用良好的單元測(cè)試手段來(lái)盡早的消除明顯的bug(當(dāng)然僅有單元測(cè)試是不夠的,畢竟跟集群的運(yùn)行環(huán)境還是不一樣的)。

       然而做mapreduce的單元測(cè)試會(huì)有一些障礙,比如Map和Reduce一些參數(shù)對(duì)象是在運(yùn)行時(shí)由hadoop框架傳入的,例如OutputCollector、Reporter、InputSplit等。這就需要有Mock手段。最初寫(xiě)mapreduce單元測(cè)試的時(shí)候自己寫(xiě)了幾個(gè)簡(jiǎn)單的Mock也基本能滿足需要,后來(lái)發(fā)現(xiàn)MRUnit比我寫(xiě)的要好用所以研究了一下就采用了。MRUnit是專門為hadoop mapreduce寫(xiě)的單元測(cè)試框架,API簡(jiǎn)潔明了,簡(jiǎn)單實(shí)用。但也有一些薄弱的地方,比如不支持MultipleOutputs(很多情況下我們會(huì)用MultipleOutputs作為多文件輸出,后面將介紹如何增強(qiáng)MRUnit使之支持MultipleOutputs)。

2 MRUnit

         MRUnit針對(duì)不同測(cè)試對(duì)象分別使用以下幾種Driver:

l  MapDriver,針對(duì)單獨(dú)的Map測(cè)試。

l  ReduceDriver,針對(duì)單獨(dú)的Reduce測(cè)試。

l  MapReduceDriver,將Map和Reduce連貫起來(lái)測(cè)試。

l  PipelineMapReduceDriver,將多個(gè)Map-Reduce pair貫串測(cè)試。

MapDriver

         單獨(dú)測(cè)試Map的例子,假設(shè)我們要計(jì)算一個(gè)賣家的平均發(fā)貨速度。Map將搜集每一次發(fā)貨的時(shí)間間隔。針對(duì)Map的測(cè)試,

         //這是被測(cè)試的Map

    private Map mapper;

    private MapDriver<LongWritable, Text, Text, TimeInfo> mapDriver;

    @Before

    public void setUp() {

        mapper = new Map();

        mapDriver = new MapDriver<LongWritable, Text, Text, TimeInfo>();

    }

 

    @Test

    public void testMap_timeFormat2() {

        String sellerId = "444";

        //模擬輸入一行(withInput),假設(shè)從這行數(shù)據(jù)中我們可以獲得賣家(sellerId)      //某一次時(shí)間間隔 為10小時(shí).

       //我們期望它輸出sellerId為key,value為代表1次10小時(shí)的TimeInfo對(duì)象。          //(withOutput)

       //如果輸入數(shù)據(jù)經(jīng)過(guò)Map計(jì)算后為期望的結(jié)果,那么測(cè)試通過(guò)。

       Text mapInputValue = new Text("……");

        mapDriver.withMapper(mapper)

              .withInput(null, mapInputValue)

              .withOutput(new Text(sellerId), new TimeInfo(1, 10))

              .runTest();

    }

ReduceDriver

         針對(duì)Reduce的單獨(dú)測(cè)試,還是這個(gè)例子。Reduce為根據(jù)Map或Combiner輸出的n次時(shí)間間隔的總和來(lái)計(jì)算平均時(shí)間。

    private Reduce reducer;

    @Before

    public void setUp() {

        reducer = new Reduce();

        reduceDriver = new ReduceDriver<Text, TimeInfo, Text,                                           LongWritable>(reducer);

    }

 

    @Test

    public void testReduce () {

        List<TimeInfo> values = new ArrayList<TimeInfo>();

        values.add(new TimeInfo(1, 3));//一次3小時(shí)

        values.add(new TimeInfo(2, 5));//兩次總共5小時(shí)

        values.add(new TimeInfo(3, 7));//三次總共7小時(shí)

       //values作為444這個(gè)賣家的reduce輸入,

       //期望計(jì)算出平均為2小時(shí)

        reduceDriver.withReducer(reducer)

                  .withInput(new Text("444"), values)

                  .withOutput(new Text("444"),new  LongWritable(2))

                  .runTest();

    }

MapReduceDriver

    以下為Map和Reduce聯(lián)合測(cè)試的例子,

    private MapReduceDriver<LongWritable, Text, Text, TimeInfo, Text, LongWritable> mrDriver;

    private Map mapper;

    private Reduce reducer;

    @Before

    public void setUp() {

        mapper = new Map();

        reducer = new Reduce();

        mrDriver = new MapReduceDriver<LongWritable, Text, Text, TimeInfo,                    Text, LongWritable>(mapper, reducer);

    }

 

    @Test

    public void testMapReduce_3record_1user() {

       Text mapInputValue1 = new Text("……");

       Text mapInputValue2 = new Text("……");

       Text mapInputValue3 = new Text("……");

       //我們期望從以上三條Map輸入計(jì)算后,

       //從reduce輸出得到444這個(gè)賣家的平均時(shí)間為2小時(shí).

        mrDriver.withInput(null, mapInputValue1)

           .withInput(null, mapInputValue2)

           .withInput(null, mapInputValue3)

           .withOutput(new Text("444"),new LongWritable(2))

           .runTest();

    }
 

增強(qiáng)MRUnit

         下面介紹為MRUnit框架增加了支持MultipleOutputs、從文件加載數(shù)據(jù)集和自動(dòng)裝配等幾個(gè)特性,使它更加便于使用。

如何支持MultipleOutputs

         然而很多場(chǎng)景下我們需要使用MultipleOutputs作為reduce的多文件輸出,MRUnit缺少支持。分析源碼后為MRUnit增強(qiáng)擴(kuò)展了兩個(gè)DriverReduceMultipleOutputsDriverMapReduceMultipleOutputDriver來(lái)支持MultipleOutputs。

 

ReduceMultipleOutputsDriver

         ReduceMultipleOutputsDriverReduceDriver的增強(qiáng)版本,假設(shè)前面例子中的Reduce使用了MultipleOutputs作為輸出,那么Reduce的測(cè)試將出現(xiàn)錯(cuò)誤。


 

使用ReduceMultipleOutputsDriver改造上面的測(cè)試用例(注意粗體部分),

private Reduce reducer;

    @Before

    public void setUp() {

        reducer = new Reduce();

       //注意這里ReduceDriver改為使用ReduceMultipleOutputsDriver

        reduceDriver = new ReduceMultipleOutputsDriver<Text, TimeInfo,                                     Text, LongWritable>(reducer);

    }

 

    @Test

    public void testReduce () {

        List<TimeInfo> values = new ArrayList<TimeInfo>();

        values.add(new TimeInfo(1, 3));//一次3小時(shí)

        values.add(new TimeInfo(2, 5));//兩次總共5小時(shí)

        values.add(new TimeInfo(3, 7));//三次總共7小時(shí)

       //values作為444這個(gè)賣家的reduce輸入,

       //期望計(jì)算出平均為2小時(shí)

        reduceDriver.withReducer(reducer)

               .withInput(new Text("444"), values)

               //Note

               //假設(shè)使用id(444)%8的方式來(lái)分文件

              //表示期望"somePrefix"+444%8這個(gè)collector將搜集到數(shù)據(jù)xxx

               . withMutiOutput ("somePrefix"+444%8,new Text("444"),new                                                     LongWritable(2))

              .runTest();

    }

 

 

 

MapReduceMultipleOutputDriver

         ReduceMultipleOutputsDriver類似,MapReduceMultipleOutputDriver用來(lái)支持使用了MultipleOutputsMap-Reduce聯(lián)合測(cè)試。MapReduceDriver一節(jié)中的例子將改為,

private MapReduceDriver<LongWritable, Text, Text, TimeInfo, Text, LongWritable> mrDriver;

    private Map mapper;

    private Reduce reducer;

    @Before

    public void setUp() {

        mapper = new Map();

        reducer = new Reduce();

       //改為使用ReduceMultipleOutputsDriver

        mrDriver = new ReduceMultipleOutputsDriver<LongWritable, Text, Text,               TimeInfo, Text, LongWritable>(mapper, reducer);

    }

 

    @Test

    public void testMapReduce_3record_1user() {

       Text mapInputValue1 = new Text("……");

       Text mapInputValue2 = new Text("……");

       Text mapInputValue3 = new Text("……");

       //我們期望從以上三條Map輸入計(jì)算后,

       //reduce輸出得到444這個(gè)賣家的平均時(shí)間為2小時(shí).

        mrDriver.withInput(null, mapInputValue1)

           .withInput(null, mapInputValue2)

           .withInput(null, mapInputValue3)

           //表示期望"somePrefix"+444%8這個(gè)collector將搜集到數(shù)據(jù)xxx

           . withMutiOutput ("somePrefix"+444%8,new Text("444"),new                                              LongWritable(2))

           .runTest();

    }

 

 

 

如何從文件加載輸入

         從以上例子看到使用MRUnit需要重復(fù)寫(xiě)很多類似的代碼,并且需要把輸入數(shù)據(jù)寫(xiě)在代碼中,顯得不是很優(yōu)雅,如果能從文件加載數(shù)據(jù)則會(huì)方便很多。因此通過(guò)使用annotation和擴(kuò)展JUnit runner,增強(qiáng)了MRUnit來(lái)解決這個(gè)問(wèn)題。

       改造上面的例子,使得map的輸入自動(dòng)從文件加載,并且消除大量使用MRUnit框架API的代碼。

@RunWith(MRUnitJunit4TestClassRunner.class)

public class XXXMRUseAnnotationTest {

 

    //表示自動(dòng)初始化mrDriver,并加載數(shù)據(jù)(如果需要)

    @MapInputSet

    @MapReduce(mapper = Map.class, reducer = Reduce.class)

     private MapReduceDriver<LongWritable, Text, Text, TimeInfo, Text, LongWritable> mrDriver;

 

    @Test

    @MapInputSet("ConsignTimeMRUseAnnotationTest.txt")//從這里加載輸入數(shù)據(jù)

    public void testMapReduce_3record_1user() {

           //只需要編寫(xiě)驗(yàn)證代碼

       mrDriver. withMutiOutput ("somePrefix"+444%8,new Text("444"),new LongWritable(2))

                                 .runTest();

    }

}

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多