Hadoop学习笔记(一) Hello, World

很早之前就知道Hadoop,却一直没去学习,一是工作上用不上,另一个则是自己总是寻不着门径写第一个Demo,信心毁于《Hadoop权威指南(第一版)》。现在还好,工作逼着自己上架,终于痛下决心,学习之。

Hadoop能干嘛?

目前我能知道的就是数据统计,比如说日志分析,数据分析,以前用数据库进行的统计,因为数据量越来越大,分析就越来越慢。Hadoop则是解决这样的问题,将一些一次写入多次读取的数据进行分布式计算统计,不但速度更快,而且能力更强(因为统计过程可以用代码逻辑,而SQL则弱得多)

大数据与Hadoop

说得很玄乎,从上面的概念来说,其实就是规模庞大的一次写入多次读取的数据,这些数据按照统计的需求被分类(建模)存储,由于数据量庞大,所以Hadoop提供了一整套技术生态来支持,也就是说,从数据的存取、计算、输出,Hadoop提供了一整套解决方案。

第一个应用

好,即然知道Hadoop是干什么的,那么我们开始写第一个程序。

需求

我们先虚构一个需求,流氓兔宇宙大型连锁超市,各子超市都向母公司提供了其各个产品的销售量数据,格式如下:

1843,44
1943,52
28443,35
223,35

数据文件每行是产品的销售量记录,使用逗号隔开,逗号左边是产品编号,右侧则是本年度的销售量。因为全宇宙销售物品数量庞大,这个的数据文件达上百亿个,流氓兔决定使用Hadoop对数据进行分析,获取每种商品的最大销售量

创建项目

1. 创建标准maven项目

2. 添加hadoop依赖

<dependencies>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-core</artifactId>
        <version>1.2.1</version>
    </dependency>
</dependencies>

3. 设置打包选项

<build>
    <finalName>demo</finalName>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.6</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>com.sanlea.hadoop.demo.Entrance</mainClass>
                        <classpathPrefix>libs/</classpathPrefix>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <version>2.8</version>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>
                            ${project.build.directory}/libs/
                        </outputDirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

这里注意mainClass的配置,其指向启动类。

分析与实现

1. 数据加工

因为商品在全宇宙都有得售卖,所以每一个数据文件都有可能有同一样商品的数据,也就是说,同一种商品,销售量在不同的数据文件中。

如果我们能读取所有的数据文件,将销售数据转化成商品 -> [销售量,销售量....]的格式,我们很容易统计每个商品的最大销售量了。

在Hadoop中Mapper就是干这样的活的,Hadoop从所有数据文件中读取每行数据,然后将每行数据传给Mapper,Mapper将这行数据进行分析,转化成key -> value方式,然后Hadoop将这些key -> value合并,最终生成key -> [value, value, ....]格式的数据。

好,我们这里开写一个Mapper:

package com.sanlea.hadoop.demo;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;

public class DataMapper extends Mapper<LongWritable, Text, Text, IntWritable>
{
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException
    {
        String line = value.toString();
        String[] parts = line.split(",");
        String product = parts[0];
        int quantity = Integer.parseInt(parts[1]);
        context.write(new Text(product), new IntWritable(quantity));
    }
}

我们写了一个DataMapper类,它继承于Mapper,泛型参数是:

  • 每行位置类型,这里可以忽略
  • 每行文本类型
  • key的类型
  • value的类型

DataMappermap方法中,value代表着数据的每一行,我们通过对每一行进行拆解,获得产品编号和销售数量,然后能过context写入结果集,以商品编号为key,以数量为value

2. 数据统计

从Mapper处,我们获得了key -> [value, value, ....]商品销售数量,我们就很容易算出这个商品的最大销售数据了,就是对value进行轮询,取得最大数即可,然后再将其写入结果key -> value

在Hadoop中,做数据统计处理的是Reduce,我们这里写这个Reduce:

package com.sanlea.hadoop.demo;


import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

public class DataReducer extends Reducer<Text, IntWritable, Text, IntWritable>
{
    @Override
    protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException
    {
        int max = Integer.MIN_VALUE;
        for (IntWritable value : values)
        {
            max = Math.max(max, value.get());
        }
        context.write(key, new IntWritable(max));
    }
}

3. 启动类

好,我们写好了数据加工的Mapper和数据统计的Reduce,那么怎么使它们联合起来一起工作呢?首先我们要建立一个任务,然后运行这个任务即可:

package com.sanlea.hadoop.demo;

import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class Entrance
{
    public static void main(String[] args) throws Exception
    {
        if (args.length < 2)
        {
            System.err.println(" Usage: demo <input path> <output path>");
            System.exit(-1);
        }

        Job job = new Job();
        job.setJarByClass(Entrance.class);
        job.setJobName("demo");

        FileInputFormat.addInputPath(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));

        job.setMapperClass(DataMapper.class);
        job.setReducerClass(DataReducer.class);

        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        System.exit(job.waitForCompletion(true) ? 0 : 1);
    }
}
  • 首先,这个程序是一个标准的Java程序,它需要两个参数,
    • 数据输入目录
    • 数据输出目录
  • 创建一个任务,设置程序入口类及名称
  • 设置任务的输入目录和输出目录
  • 设置任务的Mapper和Reduce类
  • 设置任务数据输出的Key和Value的类型
  • 运行任务直到任务完成后退出。

运行

1. 打包

mvn package

2. 运行

hadoop -jar target/demo.jar  in out

3. 查看结果

运行结果在out目录:

1981    82
1982    53
1983    64

由结果可以看出,每一种商品的最大销售量。

后语

代码是Hadoop 1.2.1版本,有点旧,主要是因为我看的书是第三版的《Hadoop权威指南》,因为Hadoop的版本混乱,导致同一个类名可能包名不同就完全不同,所以需要仔细查看上述例子代码的import语句。

这个代码运行在独立模式,虽不是真正的大数据计算,不过五脏六腑俱全,足以领悟其原意。

后续有空会继续更新,呵呵。

猜你喜欢

转载自my.oschina.net/kut/blog/1800232