很早之前就知道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的类型
在DataMapper
的map
方法中,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
语句。
这个代码运行在独立模式
,虽不是真正的大数据计算,不过五脏六腑俱全,足以领悟其原意。
后续有空会继续更新,呵呵。