2014-02-12 3 views
3

Я пытаюсь выполнить простую программу MapReduce, в которой карта принимает вход, разделяет его на две части (key => String и value => Integer) Редуктор суммирует значения для соответствующего ключа Я получаю ClassCastException каждый раз. Я не могу понять, что в коде вызывает эту ошибкуПолучение java.lang.ClassCastException: класс java.lang.String при запуске простой программы MapReduce

Мой код:

import java.io.IOException; 
import java.util.Iterator; 

import org.apache.hadoop.fs.Path; 
import org.apache.hadoop.io.LongWritable; 
import org.apache.hadoop.io.Text; 
import org.apache.hadoop.mapred.FileInputFormat; 
import org.apache.hadoop.mapred.FileOutputFormat; 
import org.apache.hadoop.mapred.JobClient; 
import org.apache.hadoop.mapred.JobConf; 
import org.apache.hadoop.mapred.MapReduceBase; 
import org.apache.hadoop.mapred.Mapper; 
import org.apache.hadoop.mapred.OutputCollector; 
import org.apache.hadoop.mapred.Reducer; 
import org.apache.hadoop.mapred.Reporter; 
import org.apache.hadoop.mapred.TextInputFormat; 
import org.apache.hadoop.mapred.TextOutputFormat; 

public class Test { 
public static class Map extends MapReduceBase implements 
     Mapper<LongWritable, Text, String, Integer> { 

    @Override 
    public void map(LongWritable key, Text value, 
      OutputCollector<String, Integer> output, Reporter reporter) 
      throws IOException { 
     String line = value.toString(); 
     String[] lineParts = line.split(","); 
     output.collect(lineParts[0], Integer.parseInt(lineParts[1])); 

    } 
} 

public static class Reduce extends MapReduceBase implements 
     Reducer<String, Integer, String, Integer> { 

    @Override 
    public void reduce(String key, Iterator<Integer> values, 
      OutputCollector<String, Integer> output, Reporter reporter) 
      throws IOException { 
     int sum = 0; 
     while (values.hasNext()) { 
      sum = sum + values.next(); 
     } 
     output.collect(key, sum); 
    } 
} 

public static void main(String[] args) throws Exception { 

    JobConf conf = new JobConf(Test.class); 
    conf.setJobName("ProductCount"); 

    conf.setMapOutputKeyClass(String.class); 
    conf.setMapOutputValueClass(Integer.class); 

    conf.setOutputKeyClass(String.class); 
    conf.setOutputValueClass(Integer.class); 

    conf.setMapperClass(Map.class); 
    conf.setReducerClass(Reduce.class); 

    conf.setInputFormat(TextInputFormat.class); 
    conf.setOutputFormat(TextOutputFormat.class); 

    FileInputFormat.setInputPaths(conf, new Path(args[0])); 
    FileOutputFormat.setOutputPath(conf, new Path(args[1])); 

    JobClient.runJob(conf); 

} 
} 

Образец данных:

abc,10 
abc,10 
abc,10 
def,9 
def,9 

Ниже трассировки стека. Это имеет какое-либо отношение к моей ключевой ценности?

14/02/11 23:57:35 INFO mapred.JobClient: Task Id : attempt_201402110240_0013_m_000001_2, Status : FAILED 
java.lang.ClassCastException: class java.lang.String 
at java.lang.Class.asSubclass(Class.java:3018) 
at org.apache.hadoop.mapred.JobConf.getOutputKeyComparator(JobConf.java:795) 
at org.apache.hadoop.mapred.MapTask$MapOutputBuffer.<init>(MapTask.java:816) 
at org.apache.hadoop.mapred.MapTask.runOldMapper(MapTask.java:382) 
at org.apache.hadoop.mapred.MapTask.run(MapTask.java:324) 
at org.apache.hadoop.mapred.Child$4.run(Child.java:268) 
at java.security.AccessController.doPrivileged(Native Method) 
at javax.security.auth.Subject.doAs(Subject.java:396) 
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1115) 
at org.apache.hadoop.mapred.Child.main(Child.java:262) 


Exception in thread "main" java.io.IOException: Job failed! 
at org.apache.hadoop.mapred.JobClient.runJob(JobClient.java:1246) 
at Test.main(Test.java:69) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
at java.lang.reflect.Method.invoke(Method.java:597) 
at org.apache.hadoop.util.RunJar.main(RunJar.java:186) 
+0

Я бы предположил, что вы используете пакет org.apache.hadoop.mapreduce вместо mapred, который является устаревшим (см. Http: // stackoverflow.com/questions/7598422/is-it-better-to-use-the-mapred-or-the-mapreduce-package-to-create-a-hadoop-job), но я не думаю, что это решит проблему , его, скорее всего, будет лучшая практика –

+0

Может ли уменить классы Integer и String с помощью IntWritable, Text? –

+0

@TomSebastian Я заменил классы, как было предложено, и теперь это работает. Не могли бы вы, пожалуйста, пролить свет на то, почему он не работает с String и Integer. Следует ли мне избегать использования классов String и Integer в качестве ключа/значения для написания программ MapReduce? Существуют ли какие-то правила для выбора классов ключа/значения? – addicted20015

ответ

1

Мне кажется, что вы не используете правильные классы для Output.

От одного из MapReduce Tutorials:

ключ и значение классы должны быть сериализуемыми рамками и, следовательно, необходимо реализовать интерфейс Writable. Кроме того, ключевые классы должны реализовать интерфейс WritableComparable, чтобы облегчить сортировку по структуре.

Поэтому вы должны заменить String.class с Text.class и Integer.class с IntWritable.class.

Надеюсь, что эта проблема решена.

Почему я не могу использовать базовые классы String или Integer?

Integer и String реализуют стандартный Serializable-интерфейс Java, как показано на рисунке docs. Проблема в том, что MapReduce сериализует/десериализует значения, не используя этот стандартный интерфейс, а скорее собственный интерфейс, который называется Writable.

Так почему бы не просто использовать базовый интерфейс Java?

Короткий ответ: Потому что он более эффективен. Writable Interface пропускает определение типа при сериализации, поскольку вы уже определяете типы ввода/вывода в вашем MapReduce-коде. Как ваш код уже знает, что будет, вместо сериализации строки так:

String: "theStringItself" 

Это может быть сериализовать как:

theStringItself 

Как вы можете видеть это экономит огромное количество памяти.

Долгосрочный ответ: Прочтите этот замечательный blog post.

Смежные вопросы