hadoop classcastexception

hadoop MultipleInputs falla con ClassCastException



(2)

Mi versión hadoop es 1.0.3, cuando uso varias entradas, recibí este error.

java.lang.ClassCastException: org.apache.hadoop.mapreduce.lib.input.TaggedInputSplit cannot be cast to org.apache.hadoop.mapreduce.lib.input.FileSplit at org.myorg.textimage$ImageMapper.setup(textimage.java:80) at org.apache.hadoop.mapreduce.Mapper.run(Mapper.java:142) at org.apache.hadoop.mapreduce.lib.input.DelegatingMapper.run(DelegatingMapper.java:55) at org.apache.hadoop.mapred.MapTask.runNewMapper(MapTask.java:764) at org.apache.hadoop.mapred.MapTask.run(MapTask.java:370) at org.apache.hadoop.mapred.Child$4.run(Child.java:255) at java.security.AccessController.doPrivileged(Native Method) at javax.security.auth.Subject.doAs(Subject.java:416) at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1121) at org.apache.hadoop.mapred.Child.main(Child.java:249)

He probado la ruta de entrada única, no hay problema. Solo cuando uso

MultipleInputs.addInputPath(job, TextInputpath, TextInputFormat.class, TextMapper.class); MultipleInputs.addInputPath(job, ImageInputpath, WholeFileInputFormat.class, ImageMapper.class);

Busqué en Google y encontré este enlace https://issues.apache.org/jira/browse/MAPREDUCE-1178 que decía que 0.21 tenía este error. Pero estoy usando 1.0.3, este error vuelve otra vez. ¿Alguien tiene el mismo problema o alguien me puede decir cómo solucionarlo? Gracias

Aquí está el código de configuración del asignador de imágenes, la 4ª línea es donde se produce el error:

protected void setup(Context context) throws IOException, InterruptedException { InputSplit split = context.getInputSplit(); Path path = ((FileSplit) split).getPath(); try { pa = new Text(path.toString()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }


Siguiendo con mi comentario, los Javadocs para TaggedInputSplit confirman que probablemente estás TaggedInputSplit erróneamente la división de entrada en un FileSplit:

/** * An {@link InputSplit} that tags another InputSplit with extra data for use * by {@link DelegatingInputFormat}s and {@link DelegatingMapper}s. */

Mi conjetura es que su método de configuración se ve algo como esto:

@Override protected void setup(Context context) throws IOException, InterruptedException { FileSplit split = (FileSplit) context.getInputSplit(); }

Lamentablemente, TaggedInputSplit no es visible al público, por lo que no puede realizar fácilmente una instanceof comprobación de estilo, seguido de una TaggedInputSplit.getInputSplit() y luego llamar a TaggedInputSplit.getInputSplit() para obtener el FileSplit subyacente real. Por lo tanto, deberá actualizar la fuente usted mismo y volver a compilar e implementar, publicar un ticket JIRA para solicitar que esto se arregle en una versión futura (si ya no se ha activado en la versión 2+) o realizar una piratería de reflejo desagradable para llegar al InputSplit subyacente

Esto está completamente sin probar:

@Override protected void setup(Context context) throws IOException, InterruptedException { InputSplit split = context.getInputSplit(); Class<? extends InputSplit> splitClass = split.getClass(); FileSplit fileSplit = null; if (splitClass.equals(FileSplit.class)) { fileSplit = (FileSplit) split; } else if (splitClass.getName().equals( "org.apache.hadoop.mapreduce.lib.input.TaggedInputSplit")) { // begin reflection hackery... try { Method getInputSplitMethod = splitClass .getDeclaredMethod("getInputSplit"); getInputSplitMethod.setAccessible(true); fileSplit = (FileSplit) getInputSplitMethod.invoke(split); } catch (Exception e) { // wrap and re-throw error throw new IOException(e); } // end reflection hackery } }

Reflexión Hackery Explicado:

Dado que TaggedInputSplit se declara ámbito protegido, no es visible para las clases fuera del paquete org.apache.hadoop.mapreduce.lib.input , y por lo tanto no puede hacer referencia a esa clase en su método de configuración. Para solucionar esto, realizamos una serie de operaciones basadas en la reflexión:

  1. Al inspeccionar el nombre de la clase, podemos probar el tipo TaggedInputSplit usando su nombre completo

    splitClass.getName().equals("org.apache.hadoop.mapreduce.lib.input.TaggedInputSplit")

  2. Sabemos que queremos llamar al método TaggedInputSplit.getInputSplit() para recuperar la división de entrada Class.getMethod(..) , por lo que utilizamos el método de reflexión Class.getMethod(..) para adquirir una referencia al método:

    Method getInputSplitMethod = splitClass.getDeclaredMethod("getInputSplit");

  3. La clase aún no es pública, por lo que usamos el método setAccessible (..) para anular esto, evitando que el administrador de seguridad lance una excepción

    getInputSplitMethod.setAccessible(true);

  4. Finalmente, invocamos el método en la referencia a la división de entrada y convertimos el resultado en un FileSplit (con optimismo, esperando que sea una instancia de este tipo):

    fileSplit = (FileSplit) getInputSplitMethod.invoke(split);


Tuve este mismo problema, pero el problema real era que todavía estaba configurando el InputFormat después de configurar los MultipleInputs:

job.setInputFormatClass(SequenceFileInputFormat.class);

Una vez que quité esta línea todo funcionó bien.