使用MapReduce分析日志文件

时间:2013-12-08 08:23:15

标签: java hadoop mapreduce

这是一个日志文件:

2011-10-26 06:11:35 user1 210.77.23.12
2011-10-26 06:11:45 user2 210.77.23.17
2011-10-26 06:11:46 user3 210.77.23.12
2011-10-26 06:11:47 user2 210.77.23.89
2011-10-26 06:11:48 user2 210.77.23.12
2011-10-26 06:11:52 user3 210.77.23.12
2011-10-26 06:11:53 user2 210.77.23.12
...

我想使用MapReduce按第三个字段(用户)的记录次数按每行的降序排序。换句话说,我希望结果显示为:

user2 4
user3 2
user1 1

现在我有两个问题:

  1. 默认情况下,MapReduce会使用 空间 回车 拆分日志文件,但我只需要第三行提交每一行,也就是说,我不关心2011-10-2606:11:35210.77.23.12等字段,如何让MapReduce省略它们并拿起用户 ?

  2. 默认情况下,MapReduce会按 而非 对结果进行排序。如何让MapReduce按 (记录时间)对结果进行排序?

  3. 谢谢。

1 个答案:

答案 0 :(得分:2)

关于你的第一个问题:

您应该将整行传递给映射器,并且每次都保留第三个标记用于映射和映射(user,1)。

public class AnalyzeLogs
{       
    public static class FindFriendMapper extends Mapper<Object, Text, Text, IntWritable> {

    public void map(Object, Text value, Context context) throws IOException, InterruptedException 
    {       
        String tempStrings[] = value.toString().split(","); 
        context.write(new Text(tempStrings[2]), new IntWritable(1));
    }
}

对于你的第二个问题,我相信你不能避免在那之后有第二个MR工作(我想不出任何其他方式)。因此,第一个作业的reducer将只聚合值并为每个键提供一个总和,按键排序。这还不是你需要的。

因此,您将此作业的输出作为输入传递给第二个MR作业。这项工作的目标是在传递给减速器之前按值进行一些特殊的排序(这绝对不会做任何事情)。

我们的第二份工作Mapper将如下:

public static class SortLogsMapper extends Mapper<Object, Text, Text, NullWritable> {

public void map(Object, Text value, Context context) throws IOException, InterruptedException 
{       
    context.write(value, new NullWritable());
}

正如您所看到的,我们根本不使用此映射器的值。相反,我们创建了一个包含我们的值的键(我们的键是key1 value1格式)。 现在还需要做的是,在框架中指定它应该基于value1而不是整个key1 value1进行排序。因此,我们将实施自定义SortComparator

public static class LogDescComparator extends WritableComparator
{
    protected LogDescComparator() 
    {
        super(Text.class, true);
    }

    @Override
    public int compare(WritableComparable w1, WritableComparable w2)
    {

        Text t1 = (Text) w1;
        Text t2 = (Text) w2;
        String[] t1Items = t1.toString().split(" "); //probably it's a " "
        String[] t2Items = t2.toString().split(" ");
        String t1Value = t1Items[1];
        String t2Value = t2Items[1];
        int comp = t2Value.compareTo(t1Value); // We compare using "real" value part of our synthetic key in Descending order

        return comp;

    }
}

您可以将自定义比较器设置为:job.setSortComparatorClass(LogDescComparator.class);

工作的减速器应该什么都不做。但是,如果我们不设置reducer,则不会对mapper键进行排序(我们需要这样做)。因此,您需要将IdentityReducer设置为第二个MR作业的Reducer,不进行缩减,但仍要确保映射器的合成键按照我们指定的方式排序。