Почему редуктор не работает правильно в моем случае? - PullRequest
1 голос
/ 01 мая 2019

почему «set» имеет только один элемент, в то время как, например, он должен иметь 4 элемента для первых 5 строк ввода, имеющих одинаковый URL-адрес и четыре разных IP-адреса. Я также использовал «для каждого» вместо «итератор», но не работает. кто-нибудь может мне помочь?

картограф

public class WordCount {

    public static class TokenizerMapper extends Mapper<Object, Text, Text, Text> {

        private Text IP = new Text();
        private Text word = new Text();

        public void map(Object key, Text value, Context context) throws IOException, InterruptedException {
            String line = value.toString();
            String[] tokens = line.split(",");
            word.set(tokens[2]);
            IP.set(tokens[0]);
            context.write(word, IP);
        }
    }

редуктор

    public static class IntSumReducer extends Reducer<Text, Text, Text, Text> {

        public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
            Set<String> set = new HashSet<String>();
            Iterator<Text> iterator = values.iterator();
            while (iterator.hasNext()) {
                set.add(iterator.next().toString());
            }
            int a = set.size();
            String str = String.format("%d", a);
            context.write(key, new Text(str));
        }
    }

работа

    public static void main(String[] args) throws Exception {
        Job job = new Job();
        job.setJarByClass(WordCount.class);
        job.setMapperClass(TokenizerMapper.class);
        job.setCombinerClass(IntSumReducer.class);
        job.setReducerClass(IntSumReducer.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(Text.class);
        FileInputFormat.addInputPath(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));
        System.exit(job.waitForCompletion(true) ? 0 : 1);       
    }
}

вход

"10.131.0.1","[29/Nov/2017:14:31:33","GET / HTTP/1.1","200"
"10.131.0.2","[29/Nov/2017:14:31:38","GET / HTTP/1.1","200"
"10.131.0.3","[29/Nov/2017:14:31:56","GET / HTTP/1.1","200"
"10.131.0.4","[29/Nov/2017:14:32:02","GET / HTTP/1.1","404"
"10.131.0.5","[29/Nov/2017:16:31:39","GET / HTTP/1.1","200"
"10.131.0.1","[29/Nov/2017:14:05:35","GET /contest.php HTTP/1.1","200"
"10.131.0.2","[29/Nov/2017:14:05:38","GET /contest.php HTTP/1.1","200"
"10.131.0.3","[29/Nov/2017:14:05:50","GET /contest.php HTTP/1.1","404"
"10.131.0.1","[29/Nov/2017:13:51:41","GET /login.php HTTP/1.1","200"
"10.131.0.2","[29/Nov/2017:13:51:49","GET /login.php HTTP/1.1","200"
"10.131.0.1","[29/Nov/2017:13:51:46","GET /contestproblem.php?name=RUET%20OJ%20Server%20Testing%20Contest HTTP/1.1","200"
"10.131.0.8","[29/Nov/2017:13:51:46","GET /contestproblen.php?name=RUET%20OJ%20Server%20Testing%20Contest HTTP/1.1","200"

мой результат

"GET / HTTP/1.1"    1
"GET /contest.php HTTP/1.1" 1
"GET /contestproblem.php?name=RUET%20OJ%20Server%20Testing%20Contest HTTP/1.1"  1
"GET /contestproblen.php?name=RUET%20OJ%20Server%20Testing%20Contest HTTP/1.1"  1
"GET /login.php HTTP/1.1"   1

1 Ответ

0 голосов
/ 02 мая 2019

Редуктор работает нормально, но Combiner не делает то, что вы думаете. Что происходит с включенным Combiner:

ВЫХОД КАРТЫ:

("GET / HTTP/1.1", "10.31.0.1")
("GET / HTTP/1.1", "10.31.0.2")

ВХОД КОМБИНИРА:

("GET / HTTP/1.1", {"10.31.0.1", "10.31.0.2"})

ВЫХОД КОМБИНИРА:

("GET / HTTP/1.1", "2") //You have the right answer here...

РЕДУКТОР ВХОДА:

("GET / HTTP/1.1", {"2"}) //...but then it gets passed into the Reducer again

РЕДУКТОР ВЫХОДА:

("GET / HTTP/1.1", "1")

В редуктор входит только один элемент, поэтому он уменьшается до «1».

Удалите Combiner (удалите job.setCombinerClass(IntSumReducer.class);, и это будет работать.

Другие рекомендуемые изменения:

  1. Имейте выход редуктора IntWritable вместо преобразования числа в Text.
  2. Сделайте Set a Set<Text> вместо Set<String>, чтобы сэкономить дорогие Text -> String преобразования.
...