En esta sesión el objetivo es escribir y leer ficheros en distintos formatos (PlainText, SequenceFile, Avro y Parquet) y distintos algoritmos de compresión y ver como se comporta cada tipo en cuanto a tiempos y memoria guiándose por las cuestiones que adjunto aquí abajo.
Los ficheros los generamos usando un programa Java que han de descargar e importar como proyecto Maven a vuestro IDE y posteriormente compilar.
Se os pedirá completar el código añadiendo dos clases que faltan y adaptar la clase Main:
- En el Package org.adilazh1.hdfs.reader añadir las clases
- MyHDFSavroReader: que implemente la interfaz MyReader para poder leer ficheros con formato Avro.
Como pista investiguen las clases DataFileReader y GenericDatumReader.
- MyHDFSparquetReader: que implemente la interfaz MyReader para poder leer ficheros con formato Parquet.
Como pista investiguen las clases ParquetReader y GenericRecord.
- MyHDFSavroReader: que implemente la interfaz MyReader para poder leer ficheros con formato Avro.
- Adaptar la clase Main para que podamos llamar a las clases creadas y deserializar los ficheros Avro y Parquet para que sean legibles para nosotros.
Descargue el proyecto aquí HDFS-1.0.
Nota: Hay un error en el código, en la clase Main, en la parte de read, para -plainText usen un objeto de la clase MyHDFSPlainFileReader en lugar de MyHDFSSequenceFileReader.
Una vez completado el proyecto (puede hallar una posible solución aquí) y compilado, úselo para responder a las cuestiones:
A qué conclusiones ha llegado?
Habrá notado que una de las características diferenciales a simple vista entre los diversos formatos es la legibilidad. Debido a los metadatos, únicamente el formato de plainText es legible para nosotros, todos los demás necesitan ser deserializados. Pero dicha característica no es la que nos hará escoger un formato u otro, nos interesara según los intereses que tengamos, ahorrar espacio o explotar paralelismo para escoger un formato u otro.
Hemos notado también que al definir SequenceFile, de estructura key-value, hemos tenido que implementar la clave. No es algo automático. Lo que nos permite concluir que un fichero puede ser almacenado en diversos formatos pero somos nosotros los que, conociendo su estructura, adaptamos el fichero al formato si es preciso.
En cuanto a los tamaños de los ficheros comparados con plainText, observamos que SequenceFile para ficheros grandes tiende a ocupar lo mismo que plainText pues sólo añade cierta metadata y clave que relativamente no supone mucho espacio. Avro, de diseño horizontal, guarda el esquema del fichero en formato JSON adjunta al fichero y eso aumenta ligeramente el espacio ocupado. Parquet en cambio observamos que el espacio ocupado es mucho menor que plainText aún que añada header y footer por cada bloque y se debe a que Parquet compacta las columnas aprovechando su diseño híbrido, así se queda con datos menos repetetivos. También representa los valores numéricos del fichero en formato numérico minimal.
En cuanto a tiempos de lectura, si no deserializamos, las conclusiones son propias de la práctica anterior, depende del tamaño y número de bloques. En cambio, si se desea deserializar y hacer el contenido legible, ahí notamos que Avro y Parquet toman más tiempo que plainText y SequenceFile dado que se necesita mayor cómputo.
La compresión nos permite ahorrar espacio, y si es de tipo splittable nos permitirá reducir el shuffling por la red en nuestros jobs distribuidos. Aquí solo hemos hecho pruebas a modo de ejemplo con SequenceFile y los tres (dos) niveles de compresión que permite: RECORD, compresión a nivel de registros (values) y BLOCK, compresión a nivel de bloques. Una compresión a nivel de bloques reduce el tamaño dado que aplica sobre más cantidad de datos, reduciendo así número de bloques y tiempo de inserción. En cuanto a tiempo de lectura, la compresión introduce cierta sobrecarga que es mayor en el nivel RECORD debido a más «partes» a descomprimir que el nivel BLOCK.
En definitiva, no existe una regla definitiva de cómo escoger un formato u otro, una compresión u otra. Depende del problema, forma de datos, utilidad de los datos, son más del tipo Hot Data o Cloud Data,… Pero lo que hemos podido observar es que Parquet ahorra bastante en espacio sin aplicar una compresión específica, pues aprovecha compactación de columnas y la manera de guardad los valores numéricos. Añadiendo una compresión, deberíamos saber si nuestros datos están más enfocados a almacenarse con poca consulta o más bien a ser explotados por algoritmos en paralelo. Para el primer caso una compresión Snappy (no splittable) sería útil. En cambio, para aprovechar al máximo el paralelismo en jobs distribuidos y usando compresión, un algoritmo a considerar sería LZO.