2017-01-18 4 views
1

Ich bekomme neben String temp = word[5]; in meinem Mapper.ArrayIndexOutofBoundsException mit Hadoop MapReduce

Ich habe das recherchiert und ich weiß, was der Fehler herkommt (wenn die Eingangsdaten leer ist oder die Länge kleiner oder größer als der Index in dem Code angegeben. Meine Daten hat einige leere Werte Zelle)

Ich habe versucht, den Array-Index Fehler mit dem folgenden Code zu fangen, aber es gibt mir immer noch einen Fehler.

import java.io.IOException; 
import java.util.*; 

import org.apache.hadoop.io.*; 
import org.apache.hadoop.mapred.*; 

public class AvgMaxTempMapper extends MapReduceBase implements Mapper<LongWritable, Text, Text, DoubleWritable> { 

    public void map(LongWritable key, Text value, OutputCollector<Text, DoubleWritable> output, Reporter reporter) throws IOException { 


    String line = value.toString(); 

    if(line != null && !line.isEmpty() && str.matches(".*\\d+.*")); 
     String [] word = line.split(","); 
     String month = word[3]; 
     String temp = word[5]; 
     if (temp.length() > 1 && temp.length() < 5){ 
      Double avgtemp = Double.parseDouble(temp); 


     output.collect(new Text(month), new DoubleWritable(avgtemp)); 
    } 
    } 
}  

Wenn Sie irgendwelche Hinweise oder Tipps geben Sie mir bitte könnte, ob der Fehler in diesem Code ist oder sollte ich woanders suchen, die eine Menge Stress ersparen!

Antwort

0

Durch das Auslösen der Ausnahme in der Methodensignatur wird der gesamte Mapper grundsätzlich angehalten, sobald eine einzelne "fehlerhafte" Datenzeile gefunden wird. Eigentlich möchten Sie, dass der Mapper diese Datenzeile ignoriert, aber andere Zeilen verarbeitet.

Sie sollten die Länge von word[] sofort nach split() überprüfen. Wenn es nicht lang genug ist, beenden Sie die Verarbeitung dieser Zeile. Sie sollten auch überprüfen, ob month und temp gültig sind, nachdem Sie sie extrahiert haben. Wie wäre es:

String [] word = line.split(","); 
if (word == null || word.length < 6) { 
    break; 
} 

String month = word[3]; 
if (month != null) { 
    break; 
} 

String temp = word[5]; 

if (temp != null && temp.length() > 1 && temp.length() < 5) { 
    try { 
     Double avgtemp = Double.parseDouble(temp); 
    } catch (NumberFormatException ex) { 
     //Log that you've seen a dodgy temperature 
     break; 
    } 
    output.collect(new Text(month), new DoubleWritable(avgtemp)); 
} 

Es ist sehr wichtig, Daten in MapReduce Jobs zu validieren, da man nie garantieren können, was Sie als Input bekommen.

Vielleicht wollen Sie auch auf Apache Commons suchen StringUtils und ArrayUtils Klassen - sie bieten Methoden wie StringUtils.isEmpty(temp) und ArrayUtils.isEmpty(word), die die oben neaten up wird.

0

Ich würde empfehlen, stattdessen einen benutzerdefinierten Zähler zu verwenden, den Sie jedes Mal erhöhen, wenn Sie eine leere Zelle finden. Dadurch erhalten Sie ein Bild davon, wie viele solcher Zeilen in Ihren Daten vorhanden sind. Zusammen mit einigen anderen Effizienzmodifikationen ist mein Vorschlag folgender:

import java.io.IOException; //do you still need this? 
import java.util.*; 

import org.apache.hadoop.io.*; 
import org.apache.hadoop.mapred.*; 

public class AvgMaxTempMapper extends MapReduceBase implements Mapper<LongWritable, Text, Text, DoubleWritable> { 

    public static enum STATS {MISSING_VALUE}; 
    private Text outKey = new Text(); 
    private DoubleWritable outValue = new DoubleWritable();  

    public void map(LongWritable key, Text value, OutputCollector<Text, DoubleWritable> output, Reporter reporter) throws IOException { 


    String line = value.toString(); 

    if(line.matches(".*\\d+.*")); 
     String [] word = line.split(","); 
     if (word.length < 6) { //or whatever else you consider expected 
      reporter.incrCounter(STATS.MISSING_VALUE,1); //you can also print/log an error message if you like     
      return; 
     } 
     String month = word[3]; 
     String temp = word[5]; 
     if (temp.length() > 1 && temp.length() < 5){ 
      Double avgtemp = Double.parseDouble(temp);     
      outKey.set(month); 
      outValue.set(avgtemp); 
      output.collect(outKey, outValue); 
     } //you were missing this '}' 
    } 
    } 

}