De acuerdo a la Hadoop - The Definitive Guide

Los registros lógicos que FileInputFormats definir no suelen encajar perfectamente en HDFS bloques. Por ejemplo, un TextInputFormat lógica de los registros son líneas que se cruzan HDFS límites más a menudo que no. Esto no influye en el funcionamiento de su programa—que las líneas no se ha perdido o roto, por ejemplo—pero vale la pena conocer, ya que significa que los datos de mapas locales (es decir, mapas que se están ejecutando en la misma máquina como sus datos de entrada) realizar algunas lecturas remotas. El leve sobrecarga esto hace que normalmente no es significativo.

Suponga una línea de registro se divide en dos bloques (b1 y b2). El asignador de procesamiento en el primer bloque (b1) dará cuenta de que la última línea no tiene un EOL separador y se obtiene el resto de la línea desde el siguiente bloque de datos (b2).

¿Cómo funciona el asignador de procesamiento en el segundo bloque (b2) determinar que el primer registro es incompleto y debe de proceso a partir del segundo registro en el bloque (b2)?

OriginalEl autor Praveen Sripati | 2013-01-12

6 Comentarios

  1. 149

    Pregunta interesante, pasé algún tiempo buscando en el código para los detalles y aquí están mis pensamientos. Las divisiones son manipulados por el cliente por InputFormat.getSplits, así que un vistazo a FileInputFormat da la siguiente información:

    • Para cada archivo de entrada, obtener la longitud del archivo, el tamaño del bloque y calcule el tamaño de división como max(minSize, min(maxSize, blockSize)) donde maxSize corresponde a mapred.max.split.size y minSize es mapred.min.split.size.
    • Dividir el archivo en diferentes FileSplits basado en el tamaño de división calculado anteriormente. Lo importante aquí es que cada FileSplit se inicializa con un start parámetro correspondiente para el desplazamiento en el archivo de entrada. Aún no hay manipulación de las líneas en ese punto. La parte pertinente del código se parece a esto:

      while (((double) bytesRemaining)/splitSize > SPLIT_SLOP) {
        int blkIndex = getBlockIndex(blkLocations, length-bytesRemaining);
        splits.add(new FileSplit(path, length-bytesRemaining, splitSize, 
                                 blkLocations[blkIndex].getHosts()));
        bytesRemaining -= splitSize;
      }
      

    Después de eso, si usted mira el LineRecordReader, el cual es definido por el TextInputFormat, que es donde las líneas se manejan:

    • Al inicializar la LineRecordReader intenta crear una instancia de un LineReader que es una abstracción para ser capaz de leer las líneas de FSDataInputStream. Hay 2 casos:
    • Si hay un CompressionCodec definido, a continuación, este códec es responsable del manejo de límites. Probablemente no sea relevante a su pregunta.
    • Si no hay ningún códec sin embargo, que es donde las cosas son muy interesante: si el start de su InputSplit es diferente de 0, entonces usted backtrack 1 carácter y, a continuación, saltar a la primera línea encuentra identificado por \n o \r\n (Windows) ! El backtrack es importante porque en caso de que su línea de límites son la misma como la división de fronteras, esto garantiza que no se salte la línea válida. Aquí está el código correspondiente:

      if (codec != null) {
         in = new LineReader(codec.createInputStream(fileIn), job);
         end = Long.MAX_VALUE;
      } else {
         if (start != 0) {
           skipFirstLine = true;
           --start;
           fileIn.seek(start);
         }
         in = new LineReader(fileIn, job);
      }
      if (skipFirstLine) {  //skip first line and re-establish "start".
        start += in.readLine(new Text(), 0,
                          (int)Math.min((long)Integer.MAX_VALUE, end - start));
      }
      this.pos = start;
      

    Así que desde las divisiones se calculan en el cliente, los cartógrafos no es necesario ejecutar en secuencia, cada mapper ya sabe si neds a descartar la primera línea o no.

    Así que, básicamente, si usted tiene 2 líneas de cada 100 mb en el mismo archivo, y para simplificar digamos que el tamaño de división es de 64 mb. Luego, cuando la entrada se divide son calculados, se tiene el siguiente escenario:

    • División 1, que contiene la ruta de acceso y los anfitriones de este bloque. Inicializa en el inicio 200-200=0Mb, longitud de 64 mb.
    • Split 2 inicializan en el inicio 200-200+64=64 mb, longitud de 64 mb.
    • Split 3 inicializan en el inicio 200-200+128=128 mb, longitud de 64 mb.
    • Split 4 inicializan en el inicio 200-200+192=192Mb, longitud de 8 mb.
    • Asignador de Un proceso de división 1, de inicio es 0, así que no saltar a la primera línea, y leer una línea completa que va más allá de los 64 mb de límite para las necesidades de lectura remota.
    • Mapper B proceso de la división 2, de inicio es != 0 para saltar a la primera línea después de 64 mb-1byte, que corresponde al final de la línea 1 en 100 mb que todavía está en la división 2, tenemos 28Mb de la línea en la división 2, de modo remoto leer el resto de 72 mb.
    • Asignador de C proceso de división 3, de inicio es != 0 para saltar a la primera línea después de 128Mb-1byte, que corresponde al final de la línea 2 en 200Mb, que es fin de archivo para no hacer nada.
    • Mapper D es el mismo como asignador de C excepto en busca de una nueva línea después de 192Mb-1byte.
    También @PraveenSripati vale la pena mencionar que el borde de los casos donde el límite estaría en \r \r\n retorno se manejan en el LineReader.readLine función, yo no creo que sea relevante a su pregunta, pero puede agregar más detalles si es necesario.
    Supongamos que hay dos líneas exactas de 64MB en la entrada y así la InputSplits suceder exactamente en la línea de límites. Así, el asignador de siempre caso omiso de la línea en el segundo bloque, porque de inicio != 0.
    En ese caso, la segunda mapper verá inicio != 0, por lo que dar marcha atrás 1 carácter, que le trae de vuelta justo antes de la \n de la primera línea y, a continuación, saltar hasta el siguiente \n. Así que saltará a la primera línea, pero el proceso de la segunda línea como se esperaba.
    es posible que la primera línea del archivo se omite alguna manera? Concretamente, he de primera línea con clave=1, y el valor de a, entonces hay dos líneas más con la misma clave en algún lugar en el archivo de clave=1, val=b, y=1, val=c. La cosa es, mi reductor obtiene {1, [b,c]} y {1, [a]} en lugar de {1, [a,b,c]}. Esto no ocurrirá si puedo añadir nueva línea al principio de mi archivo. ¿Cuál podría ser la razón, Señor?
    ¿Y si el archivo en HDFS es un binario archivo (en lugar de un archivo de texto, en el que \r\n, \n representa registro de truncamiento)?

    OriginalEl autor Charles Menguy

  2. 15

    Reducir el mapa algoritmo no funciona en los bloques físicos del fichero. Funciona en la lógica de entrada se divide. De entrada dividida depende de donde el disco fue escrito. Un registro puede extenderse a dos miembros de la comunidad.

    La manera HDFS se ha establecido, se rompe archivos muy grandes en grandes bloques (por ejemplo, la medición de 128 MB), y almacena tres copias de estos bloques en diferentes nodos en el clúster.

    HDFS no tiene conciencia de que el contenido de estos archivos. Un registro puede haber sido iniciado en Bloque-una pero al final de ese registro que pueden estar presentes en Bloque-b.

    Para resolver este problema, Hadoop utiliza una representación lógica de los datos almacenados en el archivo de bloques, conocidos como datos de entrada se divide. Cuando un trabajo MapReduce cliente calcula el de entrada se divide, descubre dónde el primer registro en un bloque comienza y donde el último registro en el bloque termina.

    El punto clave :

    En los casos donde el último registro en un bloque es incompleta, la entrada de división incluye la información de la ubicación para el siguiente bloque y el desplazamiento de bytes de los datos necesarios para completar el expediente.

    Echar un vistazo al diagrama de abajo.

    ¿Cómo Hadoop en los registros de proceso de división en el bloque de los límites?

    Un vistazo a este artículo y relacionados SE pregunta : Sobre Hadoop/división de archivos HDFS

    Más detalles se pueden leer desde documentación

    El Mapa-Reducir el framework se basa en la InputFormat del trabajo:

    1. Validar la entrada de la especificación del puesto de trabajo.
    2. Dividir el archivo de entrada(s) en lógica InputSplits, cada uno de los cuales es asignado a un individuo Mapper.
    3. Cada InputSplit a continuación, se asigna a un individuo Mapper para su procesamiento. Split podría ser tupla. InputSplit[] getSplits(JobConf job,int numSplits) es la API para tomar el cuidado de estas cosas.

    FileInputFormat, que se extiende InputFormat implementado getSplits() método. Tener una mirada en el interior de este método en grepcode

    OriginalEl autor Ravindra babu

  3. 7

    Yo lo veo de la siguiente manera: InputFormat es responsable de dividir los datos en lógica se divide teniendo en cuenta la naturaleza de los datos.
    Nada impide que lo haga, aunque se puede incrementar significativamente la latencia para el trabajo – toda la lógica y de la lectura de todo el que desee dividir el tamaño de los límites que va a suceder en el jobtracker.

    Más simple registro en cuenta el formato de entrada es TextInputFormat. Se está trabajando de la siguiente manera (como ahora por lo que he entendido el código) – formato de entrada de crear divisiones por tamaño, independientemente de las líneas, pero LineRecordReader siempre :

    a) Omitir la primera línea en la división (o parte de ella), si no es la primera división

    b) Leer una línea después de que el límite de la división en la final (si los datos que está disponible, así que no es la última división).

    Skip first line in the split (or part of it), if it is not the first split – si el primer registro en la no-primer bloque se completa, entonces no está seguro de cómo esta lógica de trabajo.
    Tan lejos como puedo ver el código de cada división de leer lo que ha + lado de la línea. Así que si salto de línea no está en el bloque de límites – está bien. Exactamente cómo se gestiona caso cuando el salto de línea es exactamente en el bloque de obligado – han de ser entendido, voy a leer el código un poco más

    OriginalEl autor David Gruzman

  4. 3

    De lo que yo he entendido, cuando el FileSplit se inicializa para el primer bloque, el constructor por defecto se llama. Por lo tanto, los valores de inicio y la longitud son cero inicialmente. Por el final de la transformación de la primera cuadra, si la última línea es incompleta, entonces el valor de la longitud será mayor que la longitud de la fractura y que va a leer la primera línea de la siguiente bloque así. Debido a esto, el valor de inicio para el primer bloque será mayor que cero y bajo esta condición, el LineRecordReader saltará a la primera línea del segundo bloque. (Ver fuente)

    En caso de que la última línea del primer bloque se completa, entonces el valor de la longitud será igual a la longitud del primer bloque y el valor de la salida para el segundo bloque será de cero. En ese caso, el LineRecordReader no saltar a la primera línea y leer el segundo bloque se forma el principio.

    Tiene sentido?

    En este escenario, los miembros de la comunidad tienen para comunicarse el uno con el otro y proceso de los bloques en la secuencia de la última línea de un bloque en particular no es completa. No estoy seguro si esta es la forma en que funciona.

    OriginalEl autor aa8y

  5. 1

    De hadoop código fuente de LineRecordReader.java el constructor: me parece que algunos comentarios :

    //If this is not the first split, we always throw away first record
    //because we always (except the last split) read one extra line in
    //next() method.
    if (start != 0) {
      start += in.readLine(new Text(), 0, maxBytesToConsume(start));
    }
    this.pos = start;
    

    de esto, yo creo hadoop leerá una línea adicional para cada división(en la final de división de corriente, lea la siguiente línea en el siguiente split), y si no es la primera división, la primera línea será tirar. de modo que no hay una línea de registro será perdido y incompletas

    OriginalEl autor Shenghai.Geng

  6. 0

    Los miembros de la comunidad no tienen para comunicarse. El archivo de bloques en HDFS y puede que el mapa actual(RecordReader) puede leer el bloque que tiene la parte restante de la línea. Esto sucede detrás de las escenas.

    OriginalEl autor user3507308

Dejar respuesta

Please enter your comment!
Please enter your name here