`
longzhun
  • 浏览: 370035 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

hadoop入门--简单的MapReduce案例

 
阅读更多

分析MapReduce执行过程

    MapReduce运行的时候,会通过Mapper运行的任务读取HDFS中的数据文件,然后调用自己的方法,处理数据,最后输出。Reducer任务会接收Mapper任务输出的数据,作为自己的输入数据,调用自己的方法,最后输出到HDFS的文件中。整个流程如图:

image

Mapper任务的执行过程详解

每个Mapper任务是一个java进程,它会读取HDFS中的文件,解析成很多的键值对,经过我们覆盖的map方法处理后,转换为很多的键值对再输出。整个Mapper任务的处理过程又可以分为以下几个阶段,如图所示。

image

在上图中,把Mapper任务的运行过程分为六个阶段。

  1. 第一阶段是把输入文件按照一定的标准分片(InputSplit),每个输入片的大小是固定的。默认情况下,输入片(InputSplit)的大小与数据块(Block)的大小是相同的。如果数据块(Block)的大小是默认值64MB,输入文件有两个,一个是32MB,一个是72MB。那么小的文件是一个输入片,大文件会分为两个数据块,那么是两个输入片。一共产生三个输入片。每一个输入片由一个Mapper进程处理。这里的三个输入片,会有三个Mapper进程处理。

  2. 第二阶段是对输入片中的记录按照一定的规则解析成键值对。有个默认规则是把每一行文本内容解析成键值对。“键”是每一行的起始位置(单位是字节),“值”是本行的文本内容。

  3. 第三阶段是调用Mapper类中的map方法。第二阶段中解析出来的每一个键值对,调用一次map方法。如果有1000个键值对,就会调用1000次map方法。每一次调用map方法会输出零个或者多个键值对。

  4. 第四阶段是按照一定的规则对第三阶段输出的键值对进行分区。比较是基于键进行的。比如我们的键表示省份(如北京、上海、山东等),那么就可以按照不同省份进行分区,同一个省份的键值对划分到一个区中。默认是只有一个区分区的数量就是Reducer任务运行的数量。默认只有一个Reducer任务。

  5. 第五阶段是对每个分区中的键值对进行排序。首先,按照键进行排序,对于键相同的键值对,按照值进行排序。比如三个键值对<2,2>、<1,3>、<2,1>,键和值分别是整数。那么排序后的结果是<1,3>、<2,1>、<2,2>。如果有第六阶段,那么进入第六阶段;如果没有,直接输出到本地的linux文件中。

  6. 第六阶段是对数据进行归约处理,也就是reduce处理。键相等的键值对会调用一次reduce方法。经过这一阶段,数据量会减少。归约后的数据输出到本地的linxu文件中。本阶段默认是没有的,需要用户自己增加这一阶段的代码

Reducer任务的执行过程详解

每个Reducer任务是一个java进程。Reducer任务接收Mapper任务的输出,归约处理后写入到HDFS中,可以分为如下图所示的几个阶段。

image

  1. 第一阶段是Reducer任务会主动从Mapper任务复制其输出的键值对。Mapper任务可能会有很多,因此Reducer会复制多个Mapper的输出。

  2. 第二阶段是把复制到Reducer本地数据,全部进行合并,即把分散的数据合并成一个大的数据。再对合并后的数据排序。

  3. 第三阶段是对排序后的键值对调用reduce方法。键相等的键值对调用一次reduce方法,每次调用会产生零个或者多个键值对。最后把这些输出的键值对写入到HDFS文件中。

在整个MapReduce程序的开发过程中,我们最大的工作量是覆盖map函数和覆盖reduce函数。

键值对的编号

在对Mapper任务、Reducer任务的分析过程中,会看到很多阶段都出现了键值对,读者容易混淆,所以这里对键值对进行编号,方便大家理解键值对的变化情况,如下图所示。

image

在上图中,对于Mapper任务输入的键值对,定义为key1和value1。在map方法中处理后,输出的键值对,定义为key2和value2。reduce方法接收key2和value2,处理后,输出key3和value3。在下文讨论键值对时,可能把key1和value1简写为<k1,v1>,key2和value2简写为<k2,v2>,key3和value3简写为<k3,v3>。

以上内容来自:http://www.superwu.cn/2013/08/21/530/

 

-----------------------分------------------割----------------线-------------------------

 

例子:求每年最高气温

在HDFS中的根目录下有以下文件格式: /input.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
2014010114
2014010216
2014010317
2014010410
2014010506
2012010609
2012010732
2012010812
2012010919
2012011023
2001010116
2001010212
2001010310
2001010411
2001010529
2013010619
2013010722
2013010812
2013010929
2013011023
2008010105
2008010216
2008010337
2008010414
2008010516
2007010619
2007010712
2007010812
2007010999
2007011023
2010010114
2010010216
2010010317
2010010410
2010010506
2015010649
2015010722
2015010812
2015010999
2015011023

 

    比如:2010012325表示在2010年01月23日的气温为25度。现在要求使用MapReduce,计算每一年出现过的最大气温。

    在写代码之前,先确保正确的导入了相关的jar包。我使用的是maven,可以到http://mvnrepository.com去搜索这几个artifactId。

    此程序需要以Hadoop文件作为输入文件,以Hadoop文件作为输出文件,因此需要用到文件系统,于是需要引入hadoop-hdfs包;我们需要向Map-Reduce集群提交任务,需要用到Map-Reduce的客户端,于是需要导入hadoop-mapreduce-client-jobclient包;另外,在处理数据的时候会用到一些hadoop的数据类型例如IntWritable和Text等,因此需要导入hadoop-common包。于是运行此程序所需要的相关依赖有以下几个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-hdfs</artifactId>
    <version>2.4.0</version>
</dependency>
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-mapreduce-client-jobclient</artifactId>
    <version>2.4.0</version>
</dependency>
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-common</artifactId>
    <version>2.4.0</version>
</dependency>

 

    包导好了后, 设计代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package com.abc.yarn;
 
import java.io.IOException;
 
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 Temperature {
    /**
     * 四个泛型类型分别代表:
     * KeyIn        Mapper的输入数据的Key,这里是每行文字的起始位置(0,11,...)
     * ValueIn      Mapper的输入数据的Value,这里是每行文字
     * KeyOut       Mapper的输出数据的Key,这里是每行文字中的“年份”
     * ValueOut     Mapper的输出数据的Value,这里是每行文字中的“气温”
     */
    static class TempMapper extends
            Mapper<LongWritable, Text, Text, IntWritable> {
        @Override
        public void map(LongWritable key, Text value, Context context)
                throws IOException, InterruptedException {
            // 打印样本: Before Mapper: 0, 2000010115
            System.out.print("Before Mapper: " + key + ", " + value);
            String line = value.toString();
            String year = line.substring(04);
            int temperature = Integer.parseInt(line.substring(8));
            context.write(new Text(year), new IntWritable(temperature));
            // 打印样本: After Mapper:2000, 15
            System.out.println(
                    "======" +
                    "After Mapper:" new Text(year) + ", " new IntWritable(temperature));
        }
    }
 
    /**
     * 四个泛型类型分别代表:
     * KeyIn        Reducer的输入数据的Key,这里是每行文字中的“年份”
     * ValueIn      Reducer的输入数据的Value,这里是每行文字中的“气温”
     * KeyOut       Reducer的输出数据的Key,这里是不重复的“年份”
     * ValueOut     Reducer的输出数据的Value,这里是这一年中的“最高气温”
     */
    static class TempReducer extends
            Reducer<Text, IntWritable, Text, IntWritable> {
        @Override
        public void reduce(Text key, Iterable<IntWritable> values,
                Context context) throws IOException, InterruptedException {
            int maxValue = Integer.MIN_VALUE;
            StringBuffer sb = new StringBuffer();
            //取values的最大值
            for (IntWritable value : values) {
                maxValue = Math.max(maxValue, value.get());
                sb.append(value).append(", ");
            }
            // 打印样本: Before Reduce: 2000, 15, 23, 99, 12, 22, 
            System.out.print("Before Reduce: " + key + ", " + sb.toString());
            context.write(key, new IntWritable(maxValue));
            // 打印样本: After Reduce: 2000, 99
            System.out.println(
                    "======" +
                    "After Reduce: " + key + ", " + maxValue);
        }
    }
 
    public static void main(String[] args) throws Exception {
        //输入路径
        String dst = "hdfs://localhost:9000/intput.txt";
        //输出路径,必须是不存在的,空文件加也不行。
        String dstOut = "hdfs://localhost:9000/output";
        Configuration hadoopConfig = new Configuration();
         
        hadoopConfig.set("fs.hdfs.impl"
            org.apache.hadoop.hdfs.DistributedFileSystem.class.getName()
        );
        hadoopConfig.set("fs.file.impl",
            org.apache.hadoop.fs.LocalFileSystem.class.getName()
        );
        Job job = new Job(hadoopConfig);
         
        //如果需要打成jar运行,需要下面这句
        //job.setJarByClass(NewMaxTemperature.class);
 
        //job执行作业时输入和输出文件的路径
        FileInputFormat.addInputPath(job, new Path(dst));
        FileOutputFormat.setOutputPath(job, new Path(dstOut));
 
        //指定自定义的Mapper和Reducer作为两个阶段的任务处理类
        job.setMapperClass(TempMapper.class);
        job.setReducerClass(TempReducer.class);
         
        //设置最后输出结果的Key和Value的类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);
         
        //执行job,直到完成
        job.waitForCompletion(true);
        System.out.println("Finished");
    }
}

 

上面代码中,注意Mapper类的泛型不是java的基本类型,而是Hadoop的数据类型Text、IntWritable。我们可以简单的等价为java的类String、int。

代码中Mapper类的泛型依次是<k1,v1,k2,v2>。map方法的第二个形参是行文本内容,是我们关心的。核心代码是把行文本内容按照空格拆分,把每行数据中“年”和“气温”提取出来,其中“年”作为新的键,“温度”作为新的值,写入到上下文context中。在这里,因为每一年有多行数据,因此每一行都会输出一个<年份, 气温>键值对。

下面是控制台打印结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Before Mapper: 02014010114======After Mapper:201414
Before Mapper: 112014010216======After Mapper:201416
Before Mapper: 222014010317======After Mapper:201417
Before Mapper: 332014010410======After Mapper:201410
Before Mapper: 442014010506======After Mapper:20146
Before Mapper: 552012010609======After Mapper:20129
Before Mapper: 662012010732======After Mapper:201232
Before Mapper: 772012010812======After Mapper:201212
Before Mapper: 882012010919======After Mapper:201219
Before Mapper: 992012011023======After Mapper:201223
Before Mapper: 1102001010116======After Mapper:200116
Before Mapper: 1212001010212======After Mapper:200112
Before Mapper: 1322001010310======After Mapper:200110
Before Mapper: 1432001010411======After Mapper:200111
Before Mapper: 1542001010529======After Mapper:200129
Before Mapper: 1652013010619======After Mapper:201319
Before Mapper: 1762013010722======After Mapper:201322
Before Mapper: 1872013010812======After Mapper:201312
Before Mapper: 1982013010929======After Mapper:201329
Before Mapper: 2092013011023======After Mapper:201323
Before Mapper: 2202008010105======After Mapper:20085
Before Mapper: 2312008010216======After Mapper:200816
Before Mapper: 2422008010337======After Mapper:200837
Before Mapper: 2532008010414======After Mapper:200814
Before Mapper: 2642008010516======After Mapper:200816
Before Mapper: 2752007010619======After Mapper:200719
Before Mapper: 2862007010712======After Mapper:200712
Before Mapper: 2972007010812======After Mapper:200712
Before Mapper: 3082007010999======After Mapper:200799
Before Mapper: 3192007011023======After Mapper:200723
Before Mapper: 3302010010114======After Mapper:201014
Before Mapper: 3412010010216======After Mapper:201016
Before Mapper: 3522010010317======After Mapper:201017
Before Mapper: 3632010010410======After Mapper:201010
Before Mapper: 3742010010506======After Mapper:20106
Before Mapper: 3852015010649======After Mapper:201549
Before Mapper: 3962015010722======After Mapper:201522
Before Mapper: 4072015010812======After Mapper:201512
Before Mapper: 4182015010999======After Mapper:201599
Before Mapper: 4292015011023======After Mapper:201523
Before Reduce: 20011210112916, ======After Reduce: 200129
Before Reduce: 20072319121299, ======After Reduce: 200799
Before Reduce: 2008161437165, ======After Reduce: 200837
Before Reduce: 2010106141617, ======After Reduce: 201017
Before Reduce: 2012191232923, ======After Reduce: 201232
Before Reduce: 20132329122219, ======After Reduce: 201329
Before Reduce: 2014146101716, ======After Reduce: 201417
Before Reduce: 20152349221299, ======After Reduce: 201599
Finished

 

    执行结果:

对分析的验证

    从打印的日志中可以看出:

  • Mapper的输入数据(k1,v1)格式是:默认的按行分的键值对<0, 2010012325>,<11, 2012010123>...

  • Reducer的输入数据格式是:把相同的键合并后的键值对:<2001, [12, 32, 25...]>,<2007, [20, 34, 30...]>...

  • Reducer的输出数(k3,v3)据格式是:经自己在Reducer中写出的格式:<2001, 32>,<2007, 34>...

    其中,由于输入数据太小,Map过程的第1阶段这里不能证明。但事实上是这样的。

    结论中第一点验证了Map过程的第2阶段“键”是每一行的起始位置(单位是字节),“值”是本行的文本内容。

    另外,通过Reduce的几行

 

1
2
3
4
5
6
7
8
Before Reduce: 20011210112916, ======After Reduce: 200129
Before Reduce: 20072319121299, ======After Reduce: 200799
Before Reduce: 2008161437165, ======After Reduce: 200837
Before Reduce: 2010106141617, ======After Reduce: 201017
Before Reduce: 2012191232923, ======After Reduce: 201232
Before Reduce: 20132329122219, ======After Reduce: 201329
Before Reduce: 2014146101716, ======After Reduce: 201417
Before Reduce: 20152349221299, ======After Reduce: 201599

 

    可以证实Map过程的第4阶段:先分区,然后对每个分区都执行一次Reduce(Map过程第6阶段)。

    对于Mapper的输出,前文中提到:如果没有Reduce过程,Mapper的输出会直接写入文件。于是我们把Reduce方法去掉(注释掉第95行即可)。

    再执行,下面是控制台打印结果: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Before Mapper: 02014010114======After Mapper:201414
Before Mapper: 112014010216======After Mapper:201416
Before Mapper: 222014010317======After Mapper:201417
Before Mapper: 332014010410======After Mapper:201410
Before Mapper: 442014010506======After Mapper:20146
Before Mapper: 552012010609======After Mapper:20129
Before Mapper: 662012010732======After Mapper:201232
Before Mapper: 772012010812======After Mapper:201212
Before Mapper: 882012010919======After Mapper:201219
Before Mapper: 992012011023======After Mapper:201223
Before Mapper: 1102001010116======After Mapper:200116
Before Mapper: 1212001010212======After Mapper:200112
Before Mapper: 1322001010310======After Mapper:200110
Before Mapper: 1432001010411======After Mapper:200111
Before Mapper: 1542001010529======After Mapper:200129
Before Mapper: 1652013010619======After Mapper:201319
Before Mapper: 1762013010722======After Mapper:201322
Before Mapper: 1872013010812======After Mapper:201312
Before Mapper: 1982013010929======After Mapper:201329
Before Mapper: 2092013011023======After Mapper:201323
Before Mapper: 2202008010105======After Mapper:20085
Before Mapper: 2312008010216======After Mapper:200816
Before Mapper: 2422008010337======After Mapper:200837
Before Mapper: 2532008010414======After Mapper:200814
Before Mapper: 2642008010516======After Mapper:200816
Before Mapper: 2752007010619======After Mapper:200719
Before Mapper: 2862007010712======After Mapper:200712
Before Mapper: 2972007010812======After Mapper:200712
Before Mapper: 3082007010999======After Mapper:200799
Before Mapper: 3192007011023======After Mapper:200723
Before Mapper: 3302010010114======After Mapper:201014
Before Mapper: 3412010010216======After Mapper:201016
Before Mapper: 3522010010317======After Mapper:201017
Before Mapper: 3632010010410======After Mapper:201010
Before Mapper: 3742010010506======After Mapper:20106
Before Mapper: 3852015010649======After Mapper:201549
Before Mapper: 3962015010722======After Mapper:201522
Before Mapper: 4072015010812======After Mapper:201512
Before Mapper: 4182015010999======After Mapper:201599
Before Mapper: 4292015011023======After Mapper:201523
Finished

 

    再来看看执行结果:

    结果还有很多行,没有截图了。

    由于没有执行Reduce操作,因此这个就是Mapper输出的中间文件的内容了。

    从打印的日志可以看出:

 

  • Mapper的输出数据(k2, v2)格式是:经自己在Mapper中写出的格式:<2010, 25>,<2012, 23>...

    从这个结果中可以看出,原数据文件中的每一行确实都有一行输出,那么Map过程的第3阶段就证实了。

 

    从这个结果中还可以看出,“年份”已经不是输入给Mapper的顺序了,这也说明了在Map过程中也按照Key执行了排序操作,即Map过程的第5阶段

分享到:
评论

相关推荐

    云帆大数据----04 MapReduce入门编程、框架原理、

    本文将对MapReduce的基本概念、编程模型、框架原理、相关组件以及入门编程实例等进行详细介绍。 MapReduce是一种分布式计算模型,能够将复杂的数据处理过程抽象为Map和Reduce两个简单的操作,从而简化并行计算的...

    Hadoop实战-陆嘉恒(高清完整版)

    《Hadoop实战-陆嘉恒(高清完整版)》是一本深入浅出介绍Hadoop技术的书籍,尤其适合初学者作为入门教材。Hadoop作为大数据处理领域的基石,其重要性不言而喻。这本书详细讲解了Hadoop的核心概念、架构以及实际应用,...

    高级软件人才培训专家-Hadoop课程资料-3-第三章 - MapReduce & YARN入门

    ### 高级软件人才培训专家-Hadoop课程资料-3-第三章 - MapReduce & YARN入门 #### 知识点一:分布式计算概述 - **定义**:分布式计算是一种计算模型,它通过网络将任务分配到多台计算机上并行处理,以提高计算效率...

    Hadoop 2 Quick-Start Guide_ Lea - Douglas Eadline

    《Hadoop 2 快速入门指南》是一本非常适合初学者和有一定经验的用户使用的书籍,它不仅涵盖了Hadoop 2.x的核心技术和特性,还提供了大量的实践指导和案例分析,有助于读者更快地掌握Hadoop的相关知识和技术。

    Hadoop开发者入门-带书签文字版

    Hadoop入门手册的高清版确保了阅读体验,清晰的文字和图表有助于理解复杂的概念。书签版则使得在大量内容中快速定位特定章节变得轻松,这对于深入学习和查找特定知识点极其重要。以下是对Hadoop开发者入门中主要知识...

    Hadoop入门到精通

    "Hadoop入门到精通"的学习资料旨在帮助初学者掌握这一强大的框架,并逐步晋升为专家。以下是对Hadoop及其相关概念的详细解读。 一、Hadoop概述 Hadoop是由Apache基金会开发的一个开源框架,主要用于处理和存储大...

    hadoop入门指南.pdf

    通过以上介绍可以看出,《Hadoop入门指南》不仅涵盖了Hadoop的基础概念、安装配置流程,还深入讲解了HDFS和MapReduce的工作原理及实际应用案例。这对于初学者来说是非常宝贵的资源,能够帮助他们快速掌握Hadoop的...

    Hadoop-HDFS-实践教程

    Hadoop是一个开源的分布式计算框架,它允许用户通过简单易用的编程模型处理大型数据集,而HDFS(Hadoop Distributed File System)是其核心组件,用于存储和处理大数据。 首先,Hadoop是一个由Apache软件基金会开发...

    Hadoop入门实战手册 中文版)

    《Hadoop入门实战手册》中可能包含多个实际案例,如日志分析、推荐系统、社交网络分析等,通过这些案例,读者可以更好地理解Hadoop在实际工作中的应用,并逐步提升解决复杂问题的能力。 总的来说,《Hadoop入门实战...

    Hadoop入门教程

    本教程《Hadoop入门教程》旨在为初学者提供全面且深入的指导,帮助他们快速理解并掌握Hadoop的基本概念、架构及应用。教程由Hadoop技术论坛在2010年出版,为当时的开发者提供了宝贵的资源。 一、Hadoop简介 Hadoop...

    hadoop入门

    总之,Hadoop入门教程为初学者提供了对Hadoop核心概念的理解,帮助他们掌握如何安装和使用Hadoop进行数据存储与处理,并理解Hadoop的设计思想和体系架构。通过学习Hadoop,初学者可以入门到大数据处理的广阔天地中,...

    Hadoop应用开发-实验指导书.doc

    主要分为以下几个部分:Hadoop环境准备与本地模式、Hadoop伪分布式集群模式、Hadoop完全分布式集群模式、HDFS Shell命令以及MapReduce入门案例wordcount。 ### Hadoop环境准备及本地模式 #### 实验目的 - 掌握...

    Hadoop mapreduce实现wordcount

    在这个案例中,我们将深入探讨如何在 Hadoop 环境中使用 MapReduce 实现 WordCount。 【描述】在 Hadoop 环境中,WordCount 的实现主要涉及两个关键阶段:Map 阶段和 Reduce 阶段。Map 阶段将原始输入数据(通常是...

    Hadoop入门手册

    【Hadoop入门手册】是一本专为初学者设计的指南,旨在帮助读者快速掌握Hadoop这一分布式计算框架的基础知识和核心概念。Hadoop是Apache软件基金会的一个开源项目,它的出现解决了大数据处理中的诸多挑战,包括数据...

    史上最全面的hadoop入门视频教程

    第四章 HDFS的JavaAPI操作和MapReduce入门 第五章 MapReduce的WordCount案例和分区 第六章 MapReduce的排序和序列化 第七章 MapReduce的运行机制和join操作 第八章 MapReduce的其他操作和yarn 第九章 数仓Hive基本...

    Hadoop大数据开发基础教学大纲.pdf

    4. MapReduce入门编程(9学时) - MapReduce原理 - MapReduce编程逻辑 - 使用Eclipse进行MapReduce开发 - 自定义键值对、Combiner和Partitioner的使用 5. MapReduce进阶编程(12学时) - MapReduce的高级应用 ...

    hadoop大数据培训零基础学习hadoop-北京尚学堂.pdf

    2. **Hadoop入门**: - 学习如何编译Hadoop源码,这对于理解其内部工作原理和进行定制化开发至关重要。 - 使用Hadoop-Eclipse-Plugin插件,可以方便地在Eclipse中远程调试Hadoop程序,这对于在本地开发并在集群上...

Global site tag (gtag.js) - Google Analytics