2010-03-31 83 views
9

Soy muy nuevo en MapReduce y completé un ejemplo de conteo de palabras de Hadoop.Recuento de palabras ordenadas usando Hadoop MapReduce

En ese ejemplo, produce archivos sin clasificar (con pares clave-valor) de recuentos de palabras. Entonces, ¿es posible ordenarlo por el número de ocurrencias de palabras combinando otra tarea de MapReduce con la anterior?

+0

Esta pregunta es bastante antigua, así que solo comentaré: Se puede hacer muy fácilmente en pig: a = load '/ out/wordcount' as (word: chararray, num: int); b = ordenar a por num; tienda b en '/ out/wordcount-sorted'; – wlk

Respuesta

0

El resultado del ejemplo del conteo de palabras de Hadoop MapReduce se ordena por la clave. Entonces la salida debe estar en orden alfabético.

Con Hadoop puede crear sus propios objetos clave que implementan la interfaz WritableComparable, lo que le permite anular el método compareTo. Esto le permite controlar el orden de clasificación.

Para crear una salida que esté ordenada por el número de ocurrencias, probablemente tenga que agregar otro trabajo de MapReduce para procesar el resultado del primero tal como lo dijo. Este segundo trabajo sería muy simple, quizás ni siquiera requiriendo una fase de reducción. Solo necesita implementar su propio objeto clave Writable para ajustar la palabra y su frecuencia. Un permiso de escritura de encargo ve algo como esto:

public class MyWritableComparable implements WritableComparable { 
     // Some data 
     private int counter; 
     private long timestamp; 

     public void write(DataOutput out) throws IOException { 
     out.writeInt(counter); 
     out.writeLong(timestamp); 
     } 

     public void readFields(DataInput in) throws IOException { 
     counter = in.readInt(); 
     timestamp = in.readLong(); 
     } 

     public int compareTo(MyWritableComparable w) { 
     int thisValue = this.value; 
     int thatValue = ((IntWritable)o).value; 
     return (thisValue < thatValue ? -1 : (thisValue==thatValue ? 0 : 1)); 
     } 
    } 

me agarró este ejemplo de here.

Probablemente deberías anular hashCode, equals y toString también.

+0

¿El método compareTo está relacionado con el ejemplo dado? –

0

En Hadoop, la clasificación se realiza entre las fases Mapa y Reducir. Un enfoque para clasificar por palabra sería usar un comparador de grupo personalizado que no agrupe nada; por lo tanto, cada llamada a reducir es solo la clave y un valor.

public class Program { 
    public static void main(String[] args) { 

     conf.setOutputKeyClass(IntWritable.class); 
     conf.setOutputValueClass(Text.clss); 
     conf.setMapperClass(Map.class); 
     conf.setReducerClass(IdentityReducer.class); 
     conf.setOutputValueGroupingComparator(GroupComparator.class); 
     conf.setNumReduceTasks(1); 
     JobClient.runJob(conf); 
    } 
} 

public class Map extends MapReduceBase implements Mapper<Text,IntWritable,IntWritable,Text> { 

    public void map(Text key, IntWritable value, OutputCollector<IntWritable,Text>, Reporter reporter) { 
     output.collect(value, key); 
    } 
} 

public class GroupComaprator extends WritableComparator { 
    protected GroupComparator() { 
     super(IntWritable.class, true); 
    } 

    public int compare(WritableComparable w1, WritableComparable w2) { 
     return -1; 
    } 
} 
+0

comparar, no comparar ... – minghan

+0

@minghan nope, ['Comparador'] (http://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html) requiere' comparar' – asgs

1

En el mapa de conteo simple de palabras reduzca el programa la salida que recibimos se ordena por palabras. Salida de ejemplo puede ser:
Manzana 1
Boy 30
Cat 2
rana 20
cebra 1
Si desea una salida a clasificar sobre la base del número de occrance de las palabras, es decir, por debajo de formato
1 Manzana 1
cebra
2 Cat
20 rana
30 Boy
puede crear otro programa MR mediante el siguiente MAPP er y reductor donde la entrada será la salida obtenida del programa de recuento simple de palabras.

class Map1 extends MapReduceBase implements Mapper<Object, Text, IntWritable, Text> 
{ 
    public void map(Object key, Text value, OutputCollector<IntWritable, Text> collector, Reporter arg3) throws IOException 
    { 
     String line = value.toString(); 
     StringTokenizer stringTokenizer = new StringTokenizer(line); 
     { 
      int number = 999; 
      String word = "empty"; 

      if(stringTokenizer.hasMoreTokens()) 
      { 
       String str0= stringTokenizer.nextToken(); 
       word = str0.trim(); 
      } 

      if(stringTokenizer.hasMoreElements()) 
      { 
       String str1 = stringTokenizer.nextToken(); 
       number = Integer.parseInt(str1.trim()); 
      } 

      collector.collect(new IntWritable(number), new Text(word)); 
     } 

    } 

} 


class Reduce1 extends MapReduceBase implements Reducer<IntWritable, Text, IntWritable, Text> 
{ 
    public void reduce(IntWritable key, Iterator<Text> values, OutputCollector<IntWritable, Text> arg2, Reporter arg3) throws IOException 
    { 
     while((values.hasNext())) 
     { 
      arg2.collect(key, values.next()); 
     } 

    } 

} 
+0

entonces ... ¿se supone que debemos agregar esto debajo del código original? ¿puedes decirme algo más específico? Soy nuevo en Java y nuevo en hadoop ... aquí está mi código: http://stackoverflow.com/questions/28785337/how-to-re-arrange-wordcount-hadoop-output-result-and-sort-them por valor – JPC

+0

También recibo este error "El tipo Mapper no puede ser una superinterfaz de Map1; una superinterfaz debe ser una interfaz" – JPC

+0

"En el conteo simple de palabras, reducir el programa la salida que obtenemos está ordenado por palabras ". Eso no es verdad – vefthym

0

Como ha dicho, una posibilidad es escribir dos trabajos para hacer esto. Primer trabajo: Ejemplo simple de conteo de palabras

Segundo trabajo: Hace la parte de clasificación.

El pseudo código podría ser:

Nota: El archivo de salida generada por el primer trabajo será la entrada para el segundo trabajo

Mapper2(String _key, Intwritable _value){ 
    //just reverse the position of _value and _key. This is useful because reducer will get the output in the sorted and shuffled manner. 
    emit(_value,_key); 
    } 

    Reduce2(IntWritable valueofMapper2,Iterable<String> keysofMapper2){ 
//At the reducer side, all the keys that have the same count are merged together. 
     for each K in keysofMapper2{ 
     emit(K,valueofMapper2); //This will sort in ascending order. 
     } 

    } 

También puede ordenar en orden descendente para los cuales es factible escribir una clase de comparación por separado, lo que hará el truco. Incluir comparador dentro del trabajo como:

Job.setComparatorclass(Comparator.class); 

Este comparador será ordenar los valores en orden descendente antes de enviar a un lado reductor. Entonces en el reductor, solo emite los valores.

Cuestiones relacionadas