Se puede pensar en este tipo de ficheros como si fueran una especie de java.util.Map.
Si listamos la carpeta de salida donde se generan estos dos ficheros:
$ hadoop-1.0.4/bin/hadoop fs -ls pruebas/poemamapfile
Found 2 items
-rw-r--r-- 1 elena supergroup 780 2013-04-22 19:42 /user/elena/pruebas/poemamapfile/data
-rw-r--r-- 1 elena supergroup 203 2013-04-22 19:42 /user/elena/pruebas/poemamapfile/index
$
El índice no guarda todos los registros, sino que guarda el valor cada cierto número de registros, por defecto 128. Es decir, el fichero de índice va a tener un formato parecido a este:
1 128
129 6079
257 12054
385 18030
513 ...
Es decir, el número de registro y el offset de éste. Como vemos, el índice contiene registros cada 128.
Si quisiéramos cambiar este intervalo, que en vez los 128 por defecto, poner otro número, usaríamos:
writer.setIndexInterval(nIntervalos);
Siendo nIntervalos cada cuántos registros queremos que se indexen. Si nIntervalos = 5, la visualización del índice sería:
1 128
6 1215
11 2410
16 3606
21 ...
Crear un MapFile
public class CreateMapFile { private static final String[] POEMA = { "El ciego sol se estrella", "en las duras aristas de las armas,", "llaga de luz los petos y espaldares", "y flamea en las puntas de las lanzas.", "El ciego sol, la sed y la fatiga", "Por la terrible estepa castellana,", "al destierro, con doce de los suyos", "-polvo, sudor y hierro- el Cid cabalga.", "Cerrado está el mesón a piedra y lodo.", "Nadie responde... Al pomo de la espada", "y al cuento de las picas el postigo", "va a ceder ¡Quema el sol, el aire abrasa!"}; private static final String rutaDestino = new String ("pruebas/poemamapfile"); public static void main(String[] args) throws IOException { Configuration conf = new Configuration(); FileSystem fs = FileSystem.get( conf); //Path path = new Path(rutaDestino); IntWritable key = new IntWritable(); Text value = new Text(); MapFile.Writer writer = new MapFile.Writer(conf, fs, rutaDestino, key.getClass(), value.getClass()); //Indico un intervalo de índice diferente a 128 (por defecto) writer.setIndexInterval(5); //No usaré posiciones consecutivas. int pos = 1; for (int i = 0; i < POEMA.length; i++) { // La key es el número de línea key.set(pos); // El value es la línea del poema correspondiente value.set(POEMA[i]); // Escribimos el par en el sequenceFile writer.append(key, value); pos += 3; } writer.close(); } }
Leer un MapFile
public class ReadMapFile { private static final String rutaDestino = new String ("pruebas/poemamapfile"); public static void main(String[] args) throws IOException, InstantiationException, IllegalAccessException { Configuration conf = new Configuration(); FileSystem fs = FileSystem.get(conf); MapFile.Reader reader = new MapFile.Reader(fs, rutaDestino, conf); IntWritable key = (IntWritable) reader.getKeyClass().newInstance(); Text value = (Text) reader.getValueClass().newInstance(); StringBuilder strBuilder; while(reader.next(key, value)){ strBuilder = new StringBuilder(key.toString()).append(" - ").append(value.toString()); System.out.println(strBuilder); } // Posiciono el reader en una key dada y conocida, si no existe la key daría un error value = (Text)reader.get(new IntWritable(7), new Text()); strBuilder = new StringBuilder(" Probando get() ").append(value.toString()); System.out.println(strBuilder); // Busco una key a partir de un valor, que si no existe, me daría el valor // siguiente más próximo y me posiciona el reader en ese lugar. key = (IntWritable) reader.getClosest(new IntWritable(11), new Text()); strBuilder = new StringBuilder(" Probando getClosest() ").append(key.toString()); System.out.println(strBuilder); reader.close(); } }
En la creación las key deben estar ordenadas, si intentamos crear un mapfile con un orden aleatorio, dará error de tipo:
Exception in thread "main" java.io.IOException: key out of order: n after m
Al igual que en los Sequence Files el MapFile.Reader nos da opciones para posicionarnos en el reader.
A través del método get(), dada una key conocida, aunque si esa key no existe al intentar acceder al Objeto devuelto nos dará error.
Y a través del método getClosest(), nos posicionaremos en el valor más próximo después de la key introducida.