Hadoop小程序:分析日志文件

来源:互联网 发布:js防刷新的倒计时代码 编辑:程序博客网 时间:2024/05/20 06:56

最近在学习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>{@Overrideprotected 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>{@Overrideprotected 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程序,对于老手来说可能是不值得一提的。由于学习的并不深入,中间可能有些错误,如有朋友发现错误,麻烦给予指正,让我能更好的学习。

0 0
原创粉丝点击