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.