通过分析hadoop的示例程序WordCount 完成统计自己的网站日志需求

通过分析示例程序WordCount, 完成统计自己的网站日志需求——统计IP地址

前几天把事示例程序运行了一下,也算是成功的

今天就测试了用MapReduce来测试下分析网站的日志,主要统计来访的IP地址的次数


我们先分析一下WordCount 的源码——以我的认知

首先我们应该知道MapReduce处理文件是分而治之,不管你有多大的文件,我把你分成几个小的来处理,给其他的服务器来处理

至于如何分,以及给那一台服务器来处理,你不用去担心,这由MapReduce框架来处理

map类处理,reduce来汇总


你需要处理的就是重新写map和reduce方法

您还需要知道的就是hadoop的一些基本数据类型

这些数据类型都实现了WritableComparable接口


BooleanWritable:标准布尔型数值
ByteWritable:单字节数值
DoubleWritable:双字节数
FloatWritable:浮点数
IntWritable:整型数
LongWritable:长整型数
Text:使用UTF8格式存储的文本
NullWritable:当<key,value>中的key或value为空时使用


知道了以上的基本知识,下面我们看看源码

public class WordCount {

  public static class TokenizerMapper 
       extends Mapper<Object, Text, Text, IntWritable>{
    
    private final static IntWritable one = new IntWritable(1);
    private Text word = new Text();
      
    public void map(Object key, Text value, Context context
                    ) throws IOException, InterruptedException {
      StringTokenizer itr = new StringTokenizer(value.toString());
      while (itr.hasMoreTokens()) {
        word.set(itr.nextToken());
        context.write(word, one);
      }
    }
  }
  
  public static class IntSumReducer 
       extends Reducer<Text,IntWritable,Text,IntWritable> {
    private IntWritable result = new IntWritable();

    public void reduce(Text key, Iterable<IntWritable> values, 
                       Context context
                       ) throws IOException, InterruptedException {
      int sum = 0;
      for (IntWritable val : values) {
        sum += val.get();
      }
      result.set(sum);
      context.write(key, result);
    }
  }

  public static void main(String[] args) throws Exception {
    Configuration conf = new Configuration();
    String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
    if (otherArgs.length < 2) {
      System.err.println("Usage: wordcount <in> [<in>...] <out>");
      System.exit(2);
    }
    Job job = Job.getInstance(conf, "word count");
    job.setJarByClass(WordCount.class);
    job.setMapperClass(TokenizerMapper.class);
    job.setCombinerClass(IntSumReducer.class);
    job.setReducerClass(IntSumReducer.class);
    job.setOutputKeyClass(Text.class);
    job.setOutputValueClass(IntWritable.class);
    for (int i = 0; i < otherArgs.length - 1; ++i) {
      FileInputFormat.addInputPath(job, new Path(otherArgs[i]));
    }
    FileOutputFormat.setOutputPath(job,
      new Path(otherArgs[otherArgs.length - 1]));
    System.exit(job.waitForCompletion(true) ? 0 : 1);
  }
}
WordCount 源码里有两个静态的内部类

TokenizerMapper和IntSumReducer


我们先看看TokenizerMapper静态内部类

TokenizerMapper继承了Mapper,并重写了map方法

map方法就是分析,比如你要统计每一个单词出现的个数,

你无需关心此时你运行的文件在那一台服务器,在那一行,你只需要知道,此时,给你的value就表示一行数据


而map里保存的key和value就是单词和单词出现次数的键值对

在源码中的这句context.write(word, one);

就表示work是key,而one是value

map就主要实现这个功能

以下代码为核心代码

StringTokenizer itr = new StringTokenizer(value.toString());
while (itr.hasMoreTokens()) {
       word.set(itr.nextToken());
       context.write(word, one);
}
需要注意的是StringTokenizer类,这个类是在java.util包下

他有很多构造函数,他可以将一个字符串进行分割

然后调用其自身的hasMoreTokens对这个字符串行遍历,迭代输出

通过查询源码发现他有三个构造方法

本例中的构造方法new StringTokenizer(value.toString(),使用 \t\n\r\f 和空格来进行分割

更多关于StringTokenizer类的信息,可以参考以下连接

java.util包的StringTokenizer类

再看看IntSumReducer类

他继承了Reducer,并重写了reduce

reduce就是对map的结果进行一个汇总

我们也看到了里面的代码,就是遍历汇总

for (IntWritable val : values) {
       sum += val.get();
}
result.set(sum);
context.write(key, result);


最后在main函数中,设置一些基本的参数即可。



下面我说说我是如何统计我的网站日志中的IP的地址的

125.71.248.8 - - [28/May/2016:06:37:40 +0800] "GET /wp-content/themes/dux/css/bootstrap.min.css?ver=1.4 HTTP/1.1" 200 16238 "http://www.028888.net/" "Mozilla/5.0 (X11; Linux x86_64; CentOS Linux release 7.2.1511 (Core)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.0 Maxthon/1.0.5.3 Safari/537.36"
代码为一条数据,事实上我的日志文件有接近6万多行,文件大小为12MB,试想一下,如果时间用传统的方法来统计,会怎么样。


上面的代码我以" - - " 进行分割。很明显,分割后的数组大小是2,第一个就是IP地址

那么我仅仅只需要修改一行代码即可

修改map中的一行代码 

StringTokenizer itr = new StringTokenizer(value.toString());
修改为:
StringTokenizer itr = new StringTokenizer(value.toString().split(" - - ")[0]);

这样我就实现了统计我最近一段时间内网站被访问的IP地址数据。

统计出来这段时间访问网站的IP地址高达5千多个,平均每个IP访问10页,最高访问25个,最低访问1次



如果您觉得本文章对您有用,也为了更好的运营博客,您可以点击这里捐助

评论 抢沙发

昵称 (必填) 邮箱 (必填)
表情
  1. #1

    来自javafan 回复给的评论 (2016-06-16 10:45:04) 回复
    正好在学习hadoop,谢谢