hadoop-mapreduce案例集

【1:】數(shù)據(jù)去重
"數(shù)據(jù)去重"主要是為了掌握和利用并行化思想來對數(shù)據(jù)進(jìn)行有意義篩選。統(tǒng)計(jì)大數(shù)據(jù)集上的數(shù)據(jù)種類個(gè)數(shù)、從網(wǎng)站日志中計(jì)算訪問地等這些看似龐雜的任務(wù)都會涉及數(shù)據(jù)去重。下面就進(jìn)入這個(gè)實(shí)例的MapReduce程序設(shè)計(jì)。

注:戴#號的是重復(fù)數(shù)據(jù)
file1數(shù)據(jù):

2012-3-1 a
2012-3-2 b
2012-3-3 c #
2012-3-4 d #
2012-3-5 a #
2012-3-6 b
2012-3-7 c
2012-3-3 c #

file2數(shù)據(jù):

2012-3-1 b
2012-3-2 a
2012-3-3 b
2012-3-4 d #
2012-3-5 a #
2012-3-6 c
2012-3-7 d
2012-3-3 c #

輸出結(jié)果:

2012-3-1 a
2012-3-1 b
2012-3-2 a
2012-3-2 b
2012-3-3 b
2012-3-3 c
2012-3-4 d
2012-3-5 a
2012-3-6 b
2012-3-6 c
2012-3-7 c
2012-3-7 d

設(shè)計(jì)思路:
數(shù)據(jù)去重最終目標(biāo)是讓原始數(shù)據(jù)出現(xiàn)次數(shù)超過一次數(shù)據(jù)輸出文件只出現(xiàn)一次。我們自然而然會想到將同一個(gè)數(shù)據(jù)的所有記錄都交給一臺reduce機(jī)器,無論這個(gè)數(shù)據(jù)出現(xiàn)多少次,只要在最終結(jié)果中輸出一次就可以了。具體就是reduce的輸入應(yīng)該以數(shù)據(jù)作為key,而對value-list則沒有要求。當(dāng)reduce接收到一個(gè)<key,value-list>時(shí)就直接將key復(fù)制到輸出的key中,并將value設(shè)置成空值。
在MapReduce流程中,map的輸出<key,value>經(jīng)過shuffle過程聚集成<key,value-list>后會交給reduce。所以從設(shè)計(jì)好的reduce輸入可以反推出map的輸出key應(yīng)為數(shù)據(jù),value任意。繼續(xù)反推,map輸出數(shù)據(jù)的key為數(shù)據(jù),而在這個(gè)實(shí)例中每個(gè)數(shù)據(jù)代表輸入文件中的一行內(nèi)容,所以map階段要完成的任務(wù)就是在采用Hadoop默認(rèn)的作業(yè)輸入方式之后,將value設(shè)置為key,并直接輸出(輸出中的value任意)。map中的結(jié)果經(jīng)過shuffle過程之后交給reduce。reduce階段不會管每個(gè)key有多少個(gè)value,它直接將輸入的key復(fù)制為輸出的key,并輸出就可以了(輸出中的value被設(shè)置成空了)。

代碼:

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class DataNoHeavy {

    public static class DataMap extends Mapper<LongWritable, Text, Text, Text>{
        
        protected void map(LongWritable key, Text value, Context context) 
                throws java.io.IOException ,InterruptedException {
            Text line = value;
            context.write(line, new Text(""));
        };
    }
    
    public static class DataReduce extends Reducer<Text, Text, Text, Text>{
    
        protected void reduce(Text key, Iterable<Text> value, Context context) 
                throws java.io.IOException ,InterruptedException {
             context.write(key, new Text(""));
        };
    }
    
    public static void main(String[] args) {
        
            Configuration conf = new Configuration();
            //設(shè)置mapper的配置,既就是hadoop/conf/mapred-site.xml的配置信息
            conf.set("mapred.job.tracker", "hadoop01:9001");        
            try {
                //新建一個(gè)Job工作
                Job job = new Job(conf);
                //設(shè)置運(yùn)行類
                job.setJarByClass(JobRun.class);
                //設(shè)置要執(zhí)行的mapper類(自己書寫的)
                job.setMapperClass(DataMap.class);
                //設(shè)置要執(zhí)行的reduce類(自己書寫的)
                job.setReducerClass(DataReduce.class);
                //設(shè)置輸出key的類型
                job.setMapOutputKeyClass(Text.class);
                //設(shè)置輸出value的類型
                job.setMapOutputValueClass(Text.class);
                
                //設(shè)置ruduce任務(wù)的個(gè)數(shù),默認(rèn)個(gè)數(shù)為一個(gè)(一般reduce的個(gè)數(shù)越多效率越高)
                job.setNumReduceTasks(1);
                
                //mapreduce 輸入數(shù)據(jù)的文件/目錄
                FileInputFormat.addInputPath(job, new Path("/usr/input/wc/Demo/dataNoHeavy"));
                //mapreduce 執(zhí)行后輸出的數(shù)據(jù)目錄
                FileOutputFormat.setOutputPath(job, new Path("/usr/output/Demo/dataNoHeavy"));
                //執(zhí)行完畢退出
                System.exit(job.waitForCompletion(true) ? 0 : 1);
                
            } catch (Exception e) {
                e.printStackTrace();
            }
    }
}

圖例:

數(shù)據(jù)去重.png

【2】數(shù)據(jù)排序
"數(shù)據(jù)排序"是許多實(shí)際任務(wù)執(zhí)行時(shí)要完成的第一項(xiàng)工作,比如學(xué)生成績評比數(shù)據(jù)建立索引等。這個(gè)實(shí)例和數(shù)據(jù)去重類似,都是原始數(shù)據(jù)進(jìn)行初步處理,為進(jìn)一步的數(shù)據(jù)操作打好基礎(chǔ)。下面進(jìn)入這個(gè)示例。

數(shù)據(jù)文件:

file1:

2
32
654
32
15
756
65223

file2:

5956
22
650
92

file3:

26
54
6

輸出結(jié)果:

1    2
2    6
3    15
4    22
5    26
6    32
7    32
8    54
9    92
10    650
11    654
12    756
13    5956
14    65223

設(shè)計(jì)思路:
這個(gè)實(shí)例僅僅要求對輸入數(shù)據(jù)進(jìn)行排序,熟悉MapReduce過程的讀者會很快想到在MapReduce過程中就有排序,是否可以利用這個(gè)默認(rèn)的排序,而不需要自己再實(shí)現(xiàn)具體的排序呢?答案是肯定的。
  但是在使用之前首先需要了解它的默認(rèn)排序規(guī)則。它是按照key值進(jìn)行排序的,如果key為封裝int的IntWritable類型,那么MapReduce按照數(shù)字大小對key排序,如果key為封裝為String的Text類型,那么MapReduce按照字典順序對字符串排序。

了解了這個(gè)細(xì)節(jié),我們就知道應(yīng)該使用封裝int的IntWritable型數(shù)據(jù)結(jié)構(gòu)了。也就是在map中將讀入的數(shù)據(jù)轉(zhuǎn)化成IntWritable型,然后作為key值輸出(value任意)。reduce拿到<key,value-list>之后,將輸入的key作為value輸出,并根據(jù)value-list元素個(gè)數(shù)決定輸出的次數(shù)。輸出的key(即代碼中的linenum)是一個(gè)全局變量,它統(tǒng)計(jì)當(dāng)前key的位次。需要注意的是這個(gè)程序中沒有配置Combiner,也就是在MapReduce過程中不使用Combiner。這主要是因?yàn)槭褂胢ap和reduce就已經(jīng)能夠完成任務(wù)了。

代碼:


import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class DataSort {
    
    public static class DataSortMap extends Mapper<LongWritable, Text, IntWritable, IntWritable> {
        protected void map(LongWritable key, Text value, Context context) 
                throws java.io.IOException ,InterruptedException {
            String line = value.toString();
            context.write(new IntWritable(Integer.parseInt(line)), new IntWritable(1));
        };
    }
    
    public static class DataSortReduce extends Reducer<IntWritable, IntWritable, IntWritable, IntWritable> {
        private static IntWritable linenum = new IntWritable(1);
        protected void reduce(IntWritable key, Iterable<IntWritable> value, Context context) 
                throws java.io.IOException ,InterruptedException {
            for(IntWritable val:value){
                context.write(linenum, key);
                linenum = new IntWritable(linenum.get()+1);
            }
        };
    }

    public static void main(String[] args) {
        Configuration conf = new Configuration();
        //設(shè)置mapper的配置,既就是hadoop/conf/mapred-site.xml的配置信息
        conf.set("mapred.job.tracker", "hadoop01:9001");        
        try {
            //新建一個(gè)Job工作
            Job job = new Job(conf);
            //設(shè)置運(yùn)行類
            job.setJarByClass(JobRun.class);
            //設(shè)置要執(zhí)行的mapper類(自己書寫的)
            job.setMapperClass(DataSortMap.class);
            //設(shè)置要執(zhí)行的reduce類(自己書寫的)
            job.setReducerClass(DataSortReduce.class);
            //設(shè)置輸出key的類型
            job.setOutputKeyClass(IntWritable.class);
            //設(shè)置輸出value的類型
            job.setOutputValueClass(IntWritable.class);
            
            //設(shè)置ruduce任務(wù)的個(gè)數(shù),默認(rèn)個(gè)數(shù)為一個(gè)(一般reduce的個(gè)數(shù)越多效率越高)
            //job.setNumReduceTasks(1);
            
            //mapreduce 輸入數(shù)據(jù)的文件/目錄
            FileInputFormat.addInputPath(job, new Path("/usr/input/wc/Demo/dataSort"));
            //mapreduce 執(zhí)行后輸出的數(shù)據(jù)目錄
            FileOutputFormat.setOutputPath(job, new Path("/usr/output/Demo/dataSort"));
            //執(zhí)行完畢退出
            System.exit(job.waitForCompletion(true) ? 0 : 1 );          
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

數(shù)據(jù)排序.png

【3】平均值
"平均成績"主要目的還是在重溫經(jīng)典"WordCount"例子,可以說是在基礎(chǔ)上的微變化版,該實(shí)例主要就是實(shí)現(xiàn)一個(gè)計(jì)算學(xué)生平均成績的例子。
 對輸入文件中數(shù)據(jù)進(jìn)行就算學(xué)生平均成績。輸入文件中的每行內(nèi)容均為一個(gè)學(xué)生姓名和他相應(yīng)的成績,如果有多門學(xué)科,則每門學(xué)科為一個(gè)文件。要求在輸出中每行有兩個(gè)間隔的數(shù)據(jù),其中,第一個(gè)代表學(xué)生的姓名第二個(gè)代表其平均成績。

數(shù)據(jù):

math:

張三    88
李四    99
王五    66
趙六    77

china:

張三    78
李四    89
王五    96
趙六    67

english:

張三    80
李四    82
王五    84
趙六    86

輸出結(jié)果:

張三    82
李四    90
王五    82
趙六    76

設(shè)計(jì)思路:
計(jì)算學(xué)生平均成績是一個(gè)仿"WordCount"例子,用來重溫一下開發(fā)MapReduce程序的流程。程序包括兩部分的內(nèi)容:Map部分和Reduce部分,分別實(shí)現(xiàn)了map和reduce的功能。
Map處理的是一個(gè)純文本文件,文件中存放的數(shù)據(jù)時(shí)每一行表示一個(gè)學(xué)生的姓名和他相應(yīng)一科成績。Mapper處理的數(shù)據(jù)是由InputFormat分解過的數(shù)據(jù)集,其中InputFormat的作用是將數(shù)據(jù)集切割成小數(shù)據(jù)集InputSplit,每一個(gè)InputSlit將由一個(gè)Mapper負(fù)責(zé)處理。此外,InputFormat中還提供了一個(gè)RecordReader的實(shí)現(xiàn),并將一個(gè)InputSplit解析成<key,value>對提供給了map函數(shù)。InputFormat的默認(rèn)值是TextInputFormat,它針對文本文件,按行將文本切割成InputSlit,并用LineRecordReader將InputSplit解析成<key,value>對,key是行在文本中的位置,value是文件中的一行。
Map的結(jié)果會通過partion分發(fā)到Reducer,Reducer做完Reduce操作后,將通過以格式OutputFormat輸出。
Mapper最終處理的結(jié)果對<key,value>,會送到Reducer中進(jìn)行合并,合并的時(shí)候,有相同key的鍵/值對則送到同一個(gè)Reducer上。Reducer是所有用戶定制Reducer類地基礎(chǔ),它的輸入是key和這個(gè)key對應(yīng)的所有value的一個(gè)迭代器,同時(shí)還有Reducer的上下文。Reduce的結(jié)果由Reducer.Context的write方法輸出到文件中。

代碼:


import java.io.IOException;
import java.util.Iterator;
import java.util.StringTokenizer;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class AvgSource {

    public static class AvgSourceMap extends Mapper<LongWritable, Text, Text, IntWritable> {
        
        protected void map(LongWritable key, Text value, Context context) 
                throws java.io.IOException ,InterruptedException {
            String line = value.toString();
            StringTokenizer tok = new StringTokenizer(line, "\n");
            while(tok.hasMoreElements()){
                String name = tok.nextToken();
                String source = tok.nextToken();
                context.write(new Text(name), new IntWritable(Integer.parseInt(source)));
            }
        };
    }
    
    public static class AvgSourceReduce extends Reducer<Text, IntWritable, Text, IntWritable> {
        
        protected void reduce(Text key, Iterable<IntWritable> value, Context context) 
                throws java.io.IOException ,InterruptedException {
            int sum = 0 ;
            int count = 0;
            Iterator<IntWritable> iterator = value.iterator();
            while(iterator.hasNext()){
                sum+= iterator.next().get();
                count++;
            }
            
            int avg = (int)sum/count;
            context.write(key, new IntWritable(avg));
            
        };
    }
    
    public static void main(String[] args) {
        Configuration conf = new Configuration();
        //設(shè)置mapper的配置,既就是hadoop/conf/mapred-site.xml的配置信息
        conf.set("mapred.job.tracker", "hadoop01:9001");
        
        try {
            //新建一個(gè)Job工作
            Job job = new Job(conf);
            //設(shè)置運(yùn)行類
            job.setJarByClass(JobRun.class);
            //設(shè)置要執(zhí)行的mapper類(自己書寫的)
            job.setMapperClass(AvgSourceMapper.class);
            //設(shè)置要執(zhí)行的reduce類(自己書寫的)
            job.setReducerClass(AvgSourceReduce.class);
            //設(shè)置輸出key的類型
            job.setMapOutputKeyClass(Text.class);
            //設(shè)置輸出value的類型
            job.setMapOutputValueClass(IntWritable.class);
            
            //設(shè)置ruduce任務(wù)的個(gè)數(shù),默認(rèn)個(gè)數(shù)為一個(gè)(一般reduce的個(gè)數(shù)越多效率越高)
            job.setNumReduceTasks(1);
            
            //mapreduce 輸入數(shù)據(jù)的文件/目錄
            FileInputFormat.addInputPath(job, new Path("/usr/input/wc/Demo/avgSource"));
            //mapreduce 執(zhí)行后輸出的數(shù)據(jù)目錄
            FileOutputFormat.setOutputPath(job, new Path("/usr/output/Demo/avgSource"));
            //執(zhí)行完畢退出
            System.exit(job.waitForCompletion(true) ? 0 : 1);
                
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

平均數(shù).png

【4】單表鏈接
前面的實(shí)例都是在數(shù)據(jù)上進(jìn)行一些簡單的處理,為進(jìn)一步的操作打基礎(chǔ)。"單表關(guān)聯(lián)"這個(gè)實(shí)例要求給出的數(shù)據(jù)尋找關(guān)心的數(shù)據(jù),它是對原始數(shù)據(jù)所包含信息的挖掘。下面進(jìn)入這個(gè)實(shí)例。

實(shí)例中給出child-parent(孩子——父母)表,要求輸出grandchild-grandparent(孫子——爺奶)表。

數(shù)據(jù):
file

child        parent
Tom        Lucy
Tom        Jack
Jone        Lucy
Jone        Jack
Lucy        Mary
Lucy        Ben
Jack        Alice
Jack        Jesse
Terry        Alice
Terry        Jesse
Philip        Terry
Philip        Alma
Mark        Terry
Mark        Alma

家譜關(guān)系:

家譜關(guān)系.png

輸出結(jié)果:

grandchild        grandparent
Tom              Alice
Tom              Jesse
Jone              Alice
Jone              Jesse
Tom              Mary
Tom              Ben
Jone              Mary
Jone              Ben
Philip              Alice
Philip              Jesse
Mark              Alice
Mark              Jesse

代碼:


import java.io.IOException;
import java.util.Iterator;
import java.util.StringTokenizer;


import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class SingleRelation {
    
    public static int time = 0;
    /*
     * map將輸出分割child和parent,然后正序輸出一次作為右表,
     * 反序輸出一次作為左表,需要注意的是在輸出的value中必須
     * 加上左右表的區(qū)別標(biāo)識。
     */
    public static class SingleRelationMap extends Mapper<LongWritable, Text, Text, Text> {
        protected void map(LongWritable key, Text value, Context context) 
                throws IOException ,InterruptedException {
            String child = new String();//孩子名字
            String parent = new String();//父母名字
            String relation = new String();//左右表標(biāo)示
            
            // 輸入的一行預(yù)處理文本
            StringTokenizer st = new StringTokenizer(value.toString());
            String[] values = new String[2];
            int i = 0;
            while(st.hasMoreTokens()){
                values[i] = st.nextToken();
                i++;
            }
            
            if(values[0].compareTo("child") != 0){
                child = values[0];
                parent = values[1];
                
                //輸出左表
                relation = "1";
                context.write(new Text(parent), new Text(relation+"+"+child+"+"+parent));
                //輸出右表
                relation = "2";
                context.write(new Text(child), new Text(relation+"+"+child+"+"+parent));
            }
        };
    }
    
    public static class SingleRelationReduce extends Reducer<Text, Text, Text, Text> {
        protected void reduce(Text key, Iterable<Text> value, Context context) 
                throws IOException ,InterruptedException {
            //輸出表頭
            if(0 == time){
                 context.write(new Text("grandchild"), new Text("grandparent"));
                 time++;
            }
            
            int grandchildnum = 0 ;
            String[] grandchild = new String[10];
            int grandparentnum = 0;
            String[] grandparent = new String[10];
            
            Iterator ite = value.iterator();
            while (ite.hasNext()) {
                String record = ite.next().toString();
                int len = record.length();
                int i = 2;
                if(0 == len){
                    continue;
                }
                
                // 取得左右表標(biāo)識
                char relation = record.charAt(0);
                // 定義孩子和父母變量
                String child = new String();
                String parent = new String();
                // 獲取value-list中value的child
                while(record.charAt(i) != '+'){
                    child += record.charAt(i);
                    i++;
                }
                
                i = i + 1;
                
                while(i < len){
                    parent += record.charAt(i);
                    i++;
                }
                
                // 左表,取出child放入grandchildren
                 if ('1' == relation) {
                     grandchild[grandchildnum] = child;
                     grandchildnum++;
                    }
                // 右表,取出parent放入grandparent
                 if ('2' == relation) {
                     grandparent[grandparentnum] = parent;
                     grandparentnum++;
                 }
                // grandchild和grandparent數(shù)組求笛卡爾兒積
            }
            
            if (0 != grandchildnum && 0 != grandparentnum) {
                for (int m = 0; m < grandchildnum; m++) {
                    for (int n = 0; n < grandparentnum; n++) {
                        // 輸出結(jié)果
                        context.write(new Text(grandchild[m]), new Text(grandparent[n]));
                    }
                }
            }
            
        };
    }

    public static void main(String[] args) {
        Configuration conf = new Configuration();
        conf.set("mapred.job.tracker", "hadoop01:9001");
        
        try {
            Job job = new Job(conf);
            job.setJarByClass(JobRun.class);
            // 設(shè)置Map和Reduce處理類
            job.setMapperClass(SingleRelationMap.class);
            job.setReducerClass(SingleRelationReduce.class);
            
            // 設(shè)置輸出類型
            job.setOutputKeyClass(Text.class);
            job.setOutputValueClass(Text.class);
            
         // 設(shè)置輸入和輸出目錄

            FileInputFormat.addInputPath(job, new Path("/usr/input/wc/Demo/single"));

            FileOutputFormat.setOutputPath(job, new Path("/usr/output/Demo/single"));

            System.exit(job.waitForCompletion(true) ? 0 : 1);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

運(yùn)行過程解析

map處理

child        parent                àà                    忽略此行
Tom        Lucy                   àà                <Lucy,1+Tom+Lucy>
                                                    <Tom,2+Tom+Lucy >
Tom        Jack                    àà                <Jack,1+Tom+Jack>
                                                    <Tom,2+Tom+Jack>
Jone        Lucy                 àà                <Lucy,1+Jone+Lucy>
                                                    <Jone,2+Jone+Lucy>
Jone        Jack                    àà                <Jack,1+Jone+Jack>
                                                    <Jone,2+Jone+Jack>
Lucy        Mary                   àà                <Mary,1+Lucy+Mary>
                                                    <Lucy,2+Lucy+Mary>
Lucy        Ben                    àà                <Ben,1+Lucy+Ben>
                                                     <Lucy,2+Lucy+Ben>
Jack        Alice                    àà                <Alice,1+Jack+Alice>
                                                      <Jack,2+Jack+Alice>
Jack        Jesse                   àà                <Jesse,1+Jack+Jesse>
                                                      <Jack,2+Jack+Jesse>
Terry        Alice                   àà                <Alice,1+Terry+Alice>
                                                      <Terry,2+Terry+Alice>
Terry        Jesse                  àà                <Jesse,1+Terry+Jesse>
                                                      <Terry,2+Terry+Jesse>
Philip        Terry                  àà                <Terry,1+Philip+Terry>
                                                      <Philip,2+Philip+Terry>
Philip        Alma                   àà                <Alma,1+Philip+Alma>
                                                      <Philip,2+Philip+Alma>
Mark        Terry                   àà                <Terry,1+Mark+Terry>
                                                      <Mark,2+Mark+Terry>
Mark        Alma                 àà                <Alma,1+Mark+Alma>
                                                      <Mark,2+Mark+Alma>

Shuffle處理

shuffle.png

reduce處理
首先由語句"
0 != grandchildnum && 0 != grandparentnum"得知,只要在"value-list"中沒有左表或者右表,則不會做處理,可以根據(jù)這條規(guī)則去除無效shuffle連接*。

2016-11-20_213049.png
然后根據(jù)下面語句進(jìn)一步對有效的shuffle連接做處理。
// 左表,取出child放入grandchildren
if ('1' == relationtype) {
    grandchild[grandchildnum] = childname;
    grandchildnum++;
}

// 右表,取出parent放入grandparent
if ('2' == relationtype) {
    grandparent[grandparentnum] = parentname;
    grandparentnum++;
}
針對一條數(shù)據(jù)進(jìn)行分析:
<Jack,1+Tom+Jack,
        1+Jone+Jack,
        2+Jack+Alice,
        2+Jack+Jesse >

分析結(jié)果左表用"字符1"表示,右表用"字符2"表示,上面的<key,value-list>中的"key"表示左表與右表連接鍵。而"value-list"表示以"key"連接左表與右表相關(guān)數(shù)據(jù)。
根據(jù)上面針對左表與右表不同的處理規(guī)則,取得兩個(gè)數(shù)組的數(shù)據(jù)如下所示:

2016-11-20_213624.png

然后根據(jù)下面語句進(jìn)行處理。

for (int m = 0; m < grandchildnum; m++) {
    for (int n = 0; n < grandparentnum; n++) {
        context.write(new Text(grandchild[m]), new Text(grandparent[n]));
    }
}
2016-11-20_214216.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 摘自:http://staticor.io/post/hadoop/2016-01-23hadoop-defini...
    wangliang938閱讀 605評論 0 1
  • github鏈接 針對Hive的優(yōu)化主要有以下幾個(gè)方面: map reduce file format shuff...
    zoyanhui閱讀 6,191評論 2 33
  • 目的這篇教程從用戶的角度出發(fā),全面地介紹了Hadoop Map/Reduce框架的各個(gè)方面。先決條件請先確認(rèn)Had...
    SeanC52111閱讀 1,755評論 0 1
  • Hadoop-Mapreduce shuffle及優(yōu)化 轉(zhuǎn)載 MapReduce簡介 在Hadoop MapRed...
    raincoffee閱讀 2,324評論 1 9
  • 早晨起來,沒化妝想去拿快遞,索性就戴個(gè)口罩吧。這還沒出門躺床上的一室友探出一個(gè)頭問,你怎么了?我說沒事,去取快遞。...
    好一只閱讀 325評論 0 0