您的位置:首页 > 移动开发 > 微信开发

Hadoop小程序:分析日志文件

2016-07-26 15:18 519 查看
最近在学习hadoop,在hadoop平台搭建完之后,写了一个小MapReduce程序。现在整理下,发在博客上,希望能和有兴趣的朋友相互学习,相互探讨。在这个例子中,我将分别展示在本地和HDFS上运行此程序。

1、准备

(1)Hadoop伪分布环境(我用的Hadoop版本是2.6.4)

(2)Eclipse

(3)原始数据:http://pan.baidu.com/s/1b0L7JK (一个上网记录的日志)

2、Hadoop平台搭建

这里不说Hadoop平台的搭建,具体文章网上很多,大家自行寻找。本文示例在HDFS上运行,是伪分布模式。

3、MapReduce程序的书写

(1)要分析的文件

日志文件格式如图1所示。每一行代表的是一条记录,各个信息之间用空格隔开,我们需要获取的是日志中网站的名称,统计各网站用户访问的次数。如第一行的“掌中新浪”,由于日志信息是有一定的格式的,网站名称出现的位置,按照制表符划分后,是第13个。所以我们获取网站名称只需用String的split方法即可。



(2)要用到的jar包

需要的jar包在hadoop-2.6.4/share/hadoop目录下,common、hdfs、mapreduce、tools、yarn每一项都有。最初只导入了几个核心包,虽然eclipse写代码是没报错,但运行起来就报错了,也不知道哪些是必须的包,索性全导入进去了,除了各个目录下的.jar,lib目录下的也要导入,总共挺多的,但能保证不报错。

(3)Map程序

Map类需要继承Mapper类,并重写map方法。先看代码:

package com.project.mr;

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

public class MyMapper extends Mapper<LongWritable, Text, Text, IntWritable>{

@Override
protected void map(LongWritable key, Text value,Context context)
throws IOException, InterruptedException {

String line = value.toString();
String[] fields = line.split("\t");
context.write(new Text(fields[12]),new IntWritable(1));
}
}


Mapper类是一个泛型类,需要自行定义四种类型,前两个是输入的key,value对,后两个是输出的。其中LongWritable、Text、IntWritable是Hadoop自己的类型,更适合数据传输,相当于Java的long、String、int。Mapper的key是每一行的偏移量,无需关心与设置,value是每一行的内容,我们需要对每一行进行处理。按“\t”将每一行分开并存入数组,取其中第13个字符串。将该字符串作为输出的key。至于value的值,由于每一行出现一次,统计为1,所以value设置为1即可。<key,value>作为Reduce类输入。
同理,Reduce类要继承Reducer类,并重写reduce方法,代码如下:

package com.project.mr;

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

public class MyReducer extends Reducer<Text, IntWritable, Text, IntWritable>{

@Override
protected void reduce(Text key, Iterable<IntWritable> values,Context context)
throws IOException, InterruptedException {

int sum = 0;
for(IntWritable value : values){
sum++;
}

context.write(key, new IntWritable(sum));

sum=0;
}
}

reduce类的输入key,value对是map类的输出,所以泛型类要自行设置为Text,IntWritable。输出的key,value是每个网站名字的统计,所以也是Text,IntWritable。reduce方法中,传入的values是一个list,例如如果“腾讯”输出是有3个值为1的value,则传入reduce的<key,values>是<"腾讯",{1,1,1}>。所以,要统计"腾讯"出现的次数,需要将该list进行累加。输出的就是<"腾讯",3>。

要运行MapReduce需要提交作业,需要写一个job类,代码如下:

package com.project.mr;

import org.apache.hadoop.conf.Configuration;
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 MyJob {

public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf, "count");
job.setJarByClass(MyJob.class);

FileInputFormat.addInputPath(job, new Path("/user/input"));
FileOutputFormat.setOutputPath(job, new Path("/user/output/1"));
job.setMapperClass(MyMapper.class);
job.setReducerClass(MyReducer.class);

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

System.exit(job.waitForCompletion(true)?0:1);
}
}
job类中,setJarByClass设置当前类编译后的.class即可,setMapperClass和setReducerClass分别为编译后的map与reduce类。setOutputKey与setOutputValue则是与输出类型相对应的.class。

(4)运行

由于我的Hadoop搭建在Linux上,在windows运行比较麻烦,最好在Linux系统中的eclipse上写,在windows上写的程序可以打成jar包在Linux的Hadoop上运行。

在本地运行时,需将FileInputFormat.addInputPath(job, new Path("/user/input"))和FileOutputFormat.setOutputPath(job, new Path("/user/output/1"))后面的path改为本地目录。

需要注意的是,如果在Hadoop上运行,需要将Hadoop文件下etc/hadoop目录下Hadoop配置文件core-site.xml与hdfs-site.xml添加到src根目录下,这样程序才会识别在HDFS上运行,否则默认在本地运行。

还有,输出路径的文件夹是不用提前创建的,让程序自己创建,否则会报错说文件夹已经存在。

运行结果是这样子的:

                           


(5)展望

reduce的输出其实可以做更进一步的处理,比如排序,去除无用的数据等。也可以结合R语言画图,让数据可视化。

本文讲的只是一个简单的MapReduce程序,对于老手来说可能是不值得一提的。由于学习的并不深入,中间可能有些错误,如有朋友发现错误,麻烦给予指正,让我能更好的学习。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  hadoop mapreduce