20200603大数据mapreduce经典案例

reducejoin


product.txt

p0001,小米5,1000,2000
p0002,锤子T1,1000,3000

orders.txt

1001,20150710,p0001,2
1002,20150710,p0002,3


/*
  K1:  LongWritable
  V1:  Text

  K2: Text  商品的id
  V2: Text  行文本信息(商品的信息)
 */
public class ReduceJoinMapper extends Mapper{
    /*

   product.txt     K1                V1

                    0                 p0001,小米5,1000,2000

   orders.txt      K1                V1
                   0                1001,20150710,p0001,2

           -------------------------------------------
                  K2                 V2

                 p0001              p0001,小米5,1000,2000


                 p0001              1001,20150710,p0001,2

     */

    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        //1:判断数据来自哪个文件
        FileSplit fileSplit = (FileSplit) context.getInputSplit();
        String fileName = fileSplit.getPath().getName();
        if(fileName.equals("product.txt")){
            //数据来自商品表
            //2:将K1和V1转为K2和V2,写入上下文中
            String[] split = value.toString().split(",");
            String productId = split[0];

            context.write(new Text(productId), value);

        }else{
            //数据来自订单表
            //2:将K1和V1转为K2和V2,写入上下文中
            String[] split = value.toString().split(",");
            String productId = split[2];
            context.write(new Text(productId), value);
        }
    }
}


public class JobMain extends Configured implements Tool {
    @Override
    public int run(String[] args) throws Exception {
        //1:获取Job对象
        Job job = Job.getInstance(super.getConf(), "reduce_join");

        //2:设置job任务
        //第一步:设置输入类和输入路径
        job.setInputFormatClass(TextInputFormat.class);
        TextInputFormat.addInputPath(job, new Path("xxxx"));

        //第二步:设置Mapper类和数据类型
        job.setMapperClass(ReduceJoinMapper.class);
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(Text.class);

        //第三,四,五,六

        //第七步:设置Reducer类和数据类型
        job.setReducerClass(ReduceJoinReducer.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(Text.class);

        //第八步:设置输出类和输出的路径
        job.setOutputFormatClass(TextOutputFormat.class);
        TextOutputFormat.setOutputPath(job, new Path("xxxxx"));

        //3:等待job任务结束
        boolean bl = job.waitForCompletion(true);

        return bl ? 0: 1;
    }

    public static void main(String[] args) throws Exception {
        Configuration configuration = new Configuration();

        //启动job任务
        int run = ToolRunner.run(configuration, new JobMain(), args);

        System.exit(run);
    }
}

输出结果:
p0001    p0001,小米5,1000,2000    1001,20150710,p0001,2
p0002    p0002,锤子T1,1000,3000    1002,20150710,p0002,3

mapreduce手机流量统计:
可自行查一下,因为数据量大且网上资料非常多


大概就是建一个手机的Bean类
然后mapreduce一下
Note:可以查下分区以及排序怎么实现,大致就是用Partitioner跟WritableComparable

共同好友:


数据:
A:B,C,D,F,E,O
B:A,C,E,K
C:A,B,D,E,I
D:A,E,F,L
E:B,C,D,M,L
F:A,B,C,D,E,O,M
G:A,C,D,E,F
H:A,C,D,E,O
I:A,O
J:B,O
K:A,C,D
L:D,E,F
M:E,F,G
O:A,H,I,J

public class Step1Mapper extends Mapper {

    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        //1.以冒泡拆分行文本数据,冒泡左边就是V2
        String[] split = value.toString().split(":");
        String userStr = split[0];

        //2.将冒泡右边的字符串以逗号拆分,每个成员就是k2
        //拿A为例子。 split1就是 B,C,D,F,E,O
        String[] split1 = split[1].split(",");
        for(String s: split1){
            //3.将k2和v2写入上下文中
            context.write(new Text(s),new Text(userStr));
        }
    }
}


public class Step1Reducer extends Reducer {

    @Override
    protected void reduce(Text key, Iterable values, Context context) throws IOException, InterruptedException {
        //1:遍历集合,并将每一个元素拼接,得到K3
        StringBuffer buffer = new StringBuffer();
        for (Text value : values) {
            buffer.append(value.toString()).append("-");
        }
        //2:K2就是V3
        //3:将K3和V3写入上下文中
        context.write(new Text(buffer.toString()), key);
    }
}


public class JobMain extends Configured implements Tool {
    @Override
    public int run(String[] args) throws Exception {
        //1:获取Job对象
        Job job = Job.getInstance(super.getConf(), "common_friends_step1_job");

        //2:设置job任务
        //第一步:设置输入类和输入路径
        job.setInputFormatClass(TextInputFormat.class);
        TextInputFormat.addInputPath(job, new Path("xxxxxx"));

        //第二步:设置Mapper类和数据类型
        job.setMapperClass(Step1Mapper.class);
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(Text.class);

        //第三,四,五,六

        //第七步:设置Reducer类和数据类型
        job.setReducerClass(Step1Reducer.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(Text.class);

        //第八步:设置输出类和输出的路径
        job.setOutputFormatClass(TextOutputFormat.class);
        TextOutputFormat.setOutputPath(job, new Path("xxxxx"));

        //3:等待job任务结束
        boolean bl = job.waitForCompletion(true);

        return bl ? 0: 1;
    }

    public static void main(String[] args) throws Exception {
        Configuration configuration = new Configuration();

        //启动job任务
        int run = ToolRunner.run(configuration, new JobMain(), args);

        System.exit(run);
    }
}


结果:
I-K-B-G-F-H-O-C-D-    A
A-F-C-J-E-    B
E-A-H-B-F-G-K-    C
K-E-C-L-A-F-H-G-    D
F-M-L-H-G-D-C-B-A-    E
G-D-A-M-L-    F
M-    G
O-    H
C-O-    I
O-    J
B-    K
D-E-    L
E-F-    M
J-I-H-A-F-    O


第二部:

public class Step2Mapper extends Mapper {
    /*
     K1           V1

     0            A-F-C-J-E-    B
    ----------------------------------

     K2             V2
     A-C            B
     A-E            B
     A-F            B
     C-E            B

     */
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        //1:拆分行文本数据,结果的第二部分可以得到V2
        String[] split = value.toString().split("\t");
        String friendStr = split[1];

        //2:继续以'-'为分隔符拆分行文本数据第一部分,得到数组
        String[] userArray = split[0].split("-");

        //3:对数组做一个排序
        Arrays.sort(userArray);

        //4:对数组中的元素进行两两组合,得到K2
        /*
          A-E-C-J ----->  A  C  E

          A  C  E
            A  C  E

         */
        for (int i = 0; i < userArray.length - 1; i++) {
            for (int j = i + 1; j < userArray.length; j++) {
                //5:将K2和V2写入上下文中
                context.write(new Text(userArray[i] + "-" + userArray[j]), new Text(friendStr));
            }
        }
    }
}

public class Step2Reducer extends Reducer {

    @Override
    protected void reduce(Text key, Iterable values, Context context) throws IOException, InterruptedException {
        //1:原来的K2就是K3
        //2:将集合进行遍历,将集合中的元素拼接,得到V3
        StringBuffer buffer = new StringBuffer();
        for (Text value : values) {
            buffer.append(value.toString()).append("-");
        }
        //3:将K3和V3写入上下文中
        context.write(key, new Text(buffer.toString()));
    }
}


public class JobMain extends Configured implements Tool {
    @Override
    public int run(String[] args) throws Exception {
        //1:获取Job对象
        Job job = Job.getInstance(super.getConf(), "common_friends_step2_job");

        //2:设置job任务
        //第一步:设置输入类和输入路径
        job.setInputFormatClass(TextInputFormat.class);
        TextInputFormat.addInputPath(job, new Path("xxxxx"));

        //第二步:设置Mapper类和数据类型
        job.setMapperClass(Step2Mapper.class);
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(Text.class);

        //第三,四,五,六

        //第七步:设置Reducer类和数据类型
        job.setReducerClass(Step2Reducer.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(Text.class);

        //第八步:设置输出类和输出的路径
        job.setOutputFormatClass(TextOutputFormat.class);
        TextOutputFormat.setOutputPath(job, new Path("xxxxx"));
        //3:等待job任务结束
        boolean bl = job.waitForCompletion(true);
        return bl ? 0 : 1;
    }

    public static void main(String[] args) throws Exception {
        Configuration configuration = new Configuration();
        //启动job任务
        int run = ToolRunner.run(configuration, new JobMain(), args);
        System.exit(run);
    }
}

结果:
A-B    C-E-
A-C    B-E-D-
A-D    F-E-
A-E    B-D-C-
A-F    O-E-D-B-C-
A-G    C-F-D-E-
A-H    O-D-C-E-
A-I    O-
A-J    B-O-
A-K    C-D-
A-L    D-E-F-
A-M    E-F-
B-C    A-E-
B-D    E-A-
B-E    C-
B-F    E-C-A-
B-G    E-A-C-
B-H    C-A-E-
B-I    A-
B-K    C-A-
B-L    E-
B-M    E-
B-O    A-
C-D    E-A-
C-E    D-B-
C-F    E-B-A-D-
C-G    D-E-A-
C-H    A-E-D-
C-I    A-
C-J    B-
C-K    A-D-
C-L    D-E-
C-M    E-
C-O    A-I-
D-E    L-
D-F    A-E-
D-G    E-F-A-
D-H    E-A-
D-I    A-
D-K    A-
D-L    E-F-
D-M    F-E-
D-O    A-
E-F    M-C-D-B-
E-G    D-C-
E-H    C-D-
E-J    B-
E-K    C-D-
E-L    D-
F-G    E-D-C-A-
F-H    A-D-O-C-E-
F-I    O-A-
F-J    B-O-
F-K    D-C-A-
F-L    E-D-
F-M    E-
F-O    A-
G-H    D-C-E-A-
G-I    A-
G-K    D-A-C-
G-L    F-D-E-
G-M    E-F-
G-O    A-
H-I    A-O-
H-J    O-
H-K    A-D-C-
H-L    E-D-
H-M    E-
H-O    A-
I-J    O-
I-K    A-
I-O    A-
K-L    D-
K-O    A-
L-M    F-E-

好评差评:
大概数据:
1    2018-03-15 22:29:06    2018-03-15 22:29:06    我想再来一个    \N    1    3    hello    来就来吧    0    2018-03-14 22:29:03
2    2018-03-15 22:42:08    2018-03-15 22:42:08    好的    \N    1    1    添加一个吧    说走咱就走啊    0    2018-03-14 22:42:04
3    2018-03-15 22:55:21    2018-03-15 22:55:21    haobuhao    \N    1    1    nihao        0    2018-03-24 22:55:17
4    2018-03-23 11:15:28    2018-03-23 11:15:28    店家很好 非常好    \N    1    3    666    谢谢    0    2018-03-23 11:15:20
5    2018-03-23 14:52:48    2018-03-23 14:53:22    a'da'd    \N    0    4    da'd's    打打操作    0    2018-03-22 14:52:42
6    2018-03-23 14:53:52    2018-03-23 14:53:52    达到    \N    1    4    1313    13132131    0    2018-03-07 14:30:38
7    2018-03-23 14:54:29    2018-03-23 14:54:29    321313    \N    1    4    111    1231231    1    2018-03-06 14:54:24
8    2018-03-23 14:54:48    2018-03-29 03:00:12    1    \N    1    4    1    110000    0    2018-03-23 14:54:42
9    2018-03-29 02:58:34    2018-03-29 02:58:34    666666666666666    \N    1    4    4444    7777777777777777    0    2018-03-01 10:58:24

public class MyOutputFormatMapper extends Mapper {

    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        context.write(value,NullWritable.get());
    }
}

public class MyRecordWriter extends RecordWriter  {

    private FSDataOutputStream goodCommentsOutputStream;
    private FSDataOutputStream badCommentsOutputStream;


    public MyRecordWriter(){

    }
    public MyRecordWriter(FSDataOutputStream goodCommentsOutputStream, FSDataOutputStream badCommentsOutputStream){
        this.goodCommentsOutputStream = goodCommentsOutputStream;
        this.badCommentsOutputStream = badCommentsOutputStream;
    }
    /**
     *
     * @param text  行文本内容
     * @param nullWritable
     * @throws IOException
     * @throws InterruptedException
     */
    @Override
    public void write(Text text, NullWritable nullWritable) throws IOException, InterruptedException {
        //1:从行文本数据中获取第9个字段
        String[] split = text.toString().split("\t");
        String numStr = split[9];

        //2:根据字段的值,判断评论的类型,然后将对应的数据写入不同的文件夹文件中
        if(Integer.parseInt(numStr) <= 1){
            //好评或者中评
            goodCommentsOutputStream.write(text.toString().getBytes());
            goodCommentsOutputStream.write("\r\n".getBytes());
        }else{
            //差评
            badCommentsOutputStream.write(text.toString().getBytes());
            badCommentsOutputStream.write("\r\n".getBytes());
        }
    }

    @Override
    public void close(TaskAttemptContext context) throws IOException, InterruptedException {
        IOUtils.closeStream(goodCommentsOutputStream);
        IOUtils.closeStream(badCommentsOutputStream);
    }
}


public class MyOutputFormat extends FileOutputFormat {
    @Override
    public RecordWriter getRecordWriter(TaskAttemptContext taskAttemptContext) throws IOException, InterruptedException {
        //1:获取目标文件的输出流(两个)
        FileSystem fileSystem = FileSystem.get(taskAttemptContext.getConfiguration());
        FSDataOutputStream goodCommentsOutputStream = fileSystem.create(new Path("xxxx/good_comments.txt"));
        FSDataOutputStream badCommentsOutputStream = fileSystem.create(new Path("xxxxx/bad_comments.txt"));

        //2:将输出流传给MyRecordWriter
        MyRecordWriter myRecordWriter = new MyRecordWriter(goodCommentsOutputStream,badCommentsOutputStream);

        return myRecordWriter;
    }
}

public class JobMain extends Configured implements Tool {
    @Override
    public int run(String[] args) throws Exception {
        //1:获取job对象
        Job job = Job.getInstance(super.getConf(), "myoutputformat_job");

        //2:设置job任务
        //第一步:设置输入类和输入的路径
        job.setInputFormatClass(TextInputFormat.class);
        TextInputFormat.addInputPath(job, new Path("xxxx"));

        //第二步:设置Mapper类和数据类型
        job.setMapperClass(MyOutputFormatMapper.class);
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(NullWritable.class);

        //第八步:设置输出类和输出的路径
        job.setOutputFormatClass(MyOutputFormat.class);
        MyOutputFormat.setOutputPath(job, new Path("xxxx"));


        //3:等待任务结束
        boolean bl = job.waitForCompletion(true);
        return bl ? 0 : 1;
    }

    public static void main(String[] args) throws Exception {
        Configuration configuration = new Configuration();
        int run = ToolRunner.run(configuration, new JobMain(), args);
        System.exit(run);
    }
}

结果example:
好评:
1    2018-03-15 22:29:06    2018-03-15 22:29:06    我想再来一个    \N    1    3    hello    来就来吧    0    2018-03-14 22:29:03
10    2018-03-29 02:58:54    2018-03-29 02:58:54    00000000    \N    1    4    55555555555    009999999    1    2018-03-02 10:58:47
100    2018-04-16 15:43:04    2018-04-16 15:43:04    买给爸爸吃的,包装有点简陋,发货挺快的,还没吃,不知道效果咋样,后面再来追评吧    \N    1    90    156******90        0    2017-12-22 09:55:46
101    2018-04-16 16:01:04    2018-04-16 16:01:04    还行吧    \N    1    84    131******13        0    2018-01-01 00:00:57
102    2018-04-16 16:01:47    2018-04-16 16:01:47    喝了 但感觉没明显的变化    \N    1    84    135******66        0    2018-03-09 13:45:37
103    2018-04-16 16:02:34    2018-04-16 16:02:34    收到的宝贝货真价实    \N    1    84    139******16        0    2018-04-03 20:30:25
104    2018-04-16 16:06:12    2018-04-16 16:06:12    刚吃,还没有发现效果,期待见效。    \N    1    82    131******85        0    2018-04-13 00:06:02
105    2018-04-16 16:06:46    2018-04-16 16:06:46    特别好用,下次再买    \N    1    82    137******77        0    2018-01-03 13:40:38
106    2018-04-16 16:07:13    2018-04-16 16:07:13    吃着没有什么感觉,说不好管用不管用    \N    1    82    136******51        0    2018-02-28 10:55:02
107    2018-04-16 16:07:38    2018-04-16 16:07:38    不错一直吃!贵在坚持吧!期待效果!!    \N    1    82    133******66        0    2018-03-21 17:40:29
108    2018-04-16 16:10:11    2018-04-16 16:10:11    看销量挺高,以前吃的在澳门买的,网上没发现卖的,只能换个牌子,吃吃这个试试    \N    1    81    131******55        0    2017-12-05 00:10:03

差评:
109    2018-04-16 16:10:55    2018-04-16 16:10:55    打开瓶子有股下水道和大粪池一样的臭味啊,臭的好恶心,不敢吃    \N    1    81    133******39        2    2017-12-20 20:50:31
11    2018-03-29 02:59:17    2018-03-29 02:59:42    311111111111    \N    0    4    999999    1333333333    2    2018-03-03 10:59:10
155    2018-04-18 12:03:36    2018-04-18 12:03:36    这奶粉大家不要买,我小孩一吃就有问题,吃两次生病两次,建议大家不要买,我现在都没有让孩子吃    \N    1    42    r***r    ,我们承诺所售商品均为百分之百的原产原装进口,有正规链路证明,海关报关单,100%正品保证,可以接受任何验证方式,请亲放心购买和使用呢!宝宝生病是多种因素影响的哦,季节变化还请妈妈们多注意下宝宝的身体情况和饮食哦,有什么问题可以及时联系我们在线客服处理,这边会给您满意的答复的,祝您生活愉快!!!    2    2017-12-13 14:40:19
156    2018-04-18 12:03:37    2018-04-18 12:04:14    这奶粉大家不要买,我小孩一吃就有问题,吃两次生病两次,建议大家不要买,我现在都没有让孩子吃    \N    0    42    r***r    ,我们承诺所售商品均为百分之百的原产原装进口,有正规链路证明,海关报关单,100%正品保证,可以接受任何验证方式,请亲放心购买和使用呢!宝宝生病是多种因素影响的哦,季节变化还请妈妈们多注意下宝宝的身体情况和饮食哦,有什么问题可以及时联系我们在线客服处理,这边会给您满意的答复的,祝您生活愉快!!!    2    2017-12-13 14:40:19
170    2018-04-18 12:31:46    2018-04-18 12:31:46    不明白一罐奶粉里有两个勺子!    \N    1    40    136******11        2    2018-01-03 12:30:40
195    2018-04-18 15:44:31    2018-04-18 15:44:31    女儿不喜欢吃,味道不好    \N    1    34    139******88    您好,羊奶粉营养成分高,是最接近母乳的奶粉,口味清淡不易上火,个人口味不一样,这个可以理解的哦~如果是换的新奶粉,也建议您给宝宝转奶适应下哦~直接换奶粉,宝宝不习惯味道吃的也会吃的比较少哦~如有疑问可联系店铺客服为您解答呢~    2    2018-04-03 14:15:22
250    2018-04-19 15:07:15    2018-04-19 15:07:15    不好不好一点也不好我家宝宝抹完就过敏    \N    1    139    137******72        2    2018-03-13 12:40:04
253    2018-04-19 15:25:40    2018-04-19 15:25:52    第一次购买,物流是真的没的说!不过打开防晒有一股发酵的酸味不好闻,都不敢用!这么贵,唉!白瞎了    \N    1    138    138******13        2    2017-12-06 14:35:30
363    2018-04-23 04:29:58    2018-04-23 04:29:58    感觉粉质有点潮潮的    \N    1    125    134******        2    2018-03-06 12:29:53
388    2018-04-23 09:46:18    2018-04-23 09:46:18    有些贵,其实是很贵!太贵了,而且也不知道怎么验证真假    \N    1    120    133******        2    2018-04-18 22:10:08
409    2018-04-23 13:50:25    2018-04-23 13:50:25    东西无两样但我帮海外购服务态度0分推诿10分    \N    1    183    131******        2    2018-01-02 21:50:18
436    2018-04-23 15:15:56    2018-04-23 15:15:56    没有前一次买的好吃    \N    1    178    134******        2    2018-04-06 23:15:50
459    2018-05-07 14:39:14    2018-05-07 14:39:14    口味非常一般不会再购买    \N    1    172    136******31        2    2018-04-11 18:39:04
469    2018-05-07 14:48:49    2018-05-07 14:49:15    订了一个月拿到货,又太难吃了    \N    1    170    131******44        2    2018-02-28 22:48:43
83    2018-04-16 14:33:47    2018-04-16 14:33:47    瓶子口有点脏 买了好几次 希望改进 发短消息说有活动 立马问客服 客服说是前几天的活动 不知道短信发了有什么意义    \N    1    94    行***键        2    2018-01-04 14:10:35

TopN:

相当重要,hive里也是重点

资料:
Order_0000001    Pdt_01    222.8
Order_0000001    Pdt_05    25.8
Order_0000002    Pdt_03    522.8
Order_0000002    Pdt_04    122.4
Order_0000002    Pdt_05    722.4
Order_0000003    Pdt_01    222.8

public class OrderBean implements WritableComparable {
    private  String orderId;
    private  Double price;

    public String getOrderId() {
        return orderId;
    }

    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return  orderId + "\t" + price;
    }

    //指定排序规则
    @Override
    public int compareTo(OrderBean orderBean) {
        //先比较订单ID,如果订单ID一致,则排序订单金额(降序)
        int i = this.orderId.compareTo(orderBean.orderId);
        if(i == 0){
            i = this.price.compareTo(orderBean.price) * -1;
        }

        return i;
    }

    //实现对象的序列化
    @Override
    public void write(DataOutput out) throws IOException {
        out.writeUTF(orderId);
        out.writeDouble(price);
    }

    //实现对象反序列化
    @Override
    public void readFields(DataInput in) throws IOException {
        this.orderId = in.readUTF();
        this.price  = in.readDouble();
    }
}


// 1: 继承WriteableComparator
public class OrderGroupComparator extends WritableComparator {
    // 2: 调用父类的有参构造
    public OrderGroupComparator() {
        super(OrderBean.class,true);
    }

    //3: 指定分组的规则(重写方法)
    @Override
    public int compare(WritableComparable a, WritableComparable b) {
        //3.1 对形参做强制类型转换
        OrderBean first = (OrderBean)a;
        OrderBean second = (OrderBean)b;

        //3.2 指定分组规则
        return first.getOrderId().compareTo(second.getOrderId());
    }
}


public class OrderPartition  extends Partitioner{
    /**
     *
     * @param orderBean K2
     * @param text  V2
     * @param i  ReduceTask个数
     * @return 返回分区的编号
     */
    @Override
    public int getPartition(OrderBean orderBean, Text text, int i) {
        return (orderBean.getOrderId().hashCode() & 2147483647) % i;   //分区规则,相同的key分到一组,2147483647为整型最大数,为什么取这个没看到讲解,但我猜用这个可以减少hash冲突
    }
}

public class GroupMapper extends Mapper {
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        //1:拆分行文本数据,得到订单的ID,订单的金额
        String[] split = value.toString().split("\t");

        //2:封装OrderBean,得到K2
        OrderBean orderBean = new OrderBean();
        orderBean.setOrderId(split[0]);
        orderBean.setPrice(Double.valueOf(split[2]));

        //3:将K2和V2写入上下文中
        context.write(orderBean, value);
    }
}

public class GroupReducer extends Reducer {
    @Override
    protected void reduce(OrderBean key, Iterable values, Context context) throws IOException, InterruptedException {
        int i = 0;
        for (Text value : values) {
            context.write(value, NullWritable.get());
            i++;
            if (i >= 2) {   //取top2
                break;
            }
        }
    }
}

public class JobMain extends Configured implements Tool {
    @Override
    public int run(String[] args) throws Exception {
        //1:获取Job对象
        Job job = Job.getInstance(super.getConf(), "mygroup_job");

        //2:设置job任务
        //第一步:设置输入类和输入路径
        job.setInputFormatClass(TextInputFormat.class);
        TextInputFormat.addInputPath(job, new Path("xxxxx"));

        //第二步:设置Mapper类和数据类型
        job.setMapperClass(GroupMapper.class);
        job.setMapOutputKeyClass(OrderBean.class);
        job.setMapOutputValueClass(Text.class);

        //第三,四,五,六
        //设置分区
        job.setPartitionerClass(OrderPartition.class);
        //设置分组
        job.setGroupingComparatorClass(OrderGroupComparator.class);

        //第七步:设置Reducer类和数据类型
        job.setReducerClass(GroupReducer.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(NullWritable.class);

        //第八步:设置输出类和输出的路径
        job.setOutputFormatClass(TextOutputFormat.class);
        TextOutputFormat.setOutputPath(job, new Path("xxxx"));

        //3:等待job任务结束
        boolean bl = job.waitForCompletion(true);
        return bl ? 0: 1;
    }

    public static void main(String[] args) throws Exception {
        Configuration configuration = new Configuration();

        //启动job任务
        int run = ToolRunner.run(configuration, new JobMain(), args);

        System.exit(run);
    }
}


最后结果:
Order_0000001    Pdt_01    222.8
Order_0000001    Pdt_05    25.8
Order_0000002    Pdt_05    722.4
Order_0000002    Pdt_03    522.8
Order_0000003    Pdt_01    222.8

你可能感兴趣的:(大数据之路,mapreduce)