2015-12-14 3 views
5

Я читал о mapreduce, и мне было интересно узнать о конкретном сценарии. Допустим, у нас есть несколько файлов (fileA, fileB, fileC, например), каждая из которых состоит из нескольких целых чисел. Если мы хотим, чтобы отсортировать числа из всех файлов, чтобы создать что-то вроде этого:MapReduce example

23 fileA 
34 fileB 
35 fileA 
60 fileA 
60 fileC 

как бы карта и сократить процесс работы?

В настоящее время это то, что у меня есть, но это не совсем правильно;

  1. (fileName, fileContent) -> (map to) (Number, fileName)

  2. рода ключ, пары временных значений и получить (Number, (list of){fileName1, fileName2...})

  3. Снизить временные пары и получить

    (Number, fileName1) 
    (Number, fileName2) 
    

    и так далее

Проблема заключается в том, что на этапе сортировки имена файлов могут быть не в алфавитном порядке, и поэтому часть уменьшения не будет генерировать правильный результат. Может ли кто-нибудь дать представление о правильном подходе к этому сценарию?

+0

Вы имеете в виду, что вы хотите, чтобы и номера, и имена файлов были отсортированы. Напр. «23 файлаA», «35 файлов», «60 файлов», «34 файла», «60 файлов»? Здесь все записи «fileA» отображаются сначала в отсортированном порядке, а затем в файле B, а затем в filcC. Это то, что вы хотите? Просьба уточнить. Исходя из этого, я могу видеть, могу ли я предоставить answe –

+0

Оба числа и имена файлов должны сортироваться, но не отдельно. Номера и имена файлов должны быть смешаны вместе, как пример выше. – Dobby

+0

Вы можете сделать это с помощью составных клавиш или с использованием вторичной сортировки. – YoungHobbit

ответ

3

Лучший способ достичь этого - вторичный сорт. Вам нужно отсортировать оба ключа (в номерах вашего номера) и значения (в именах файлов вашего случая). В Hadoop выход картографа сортируется только по клавишам.

Это может быть достигнуто с помощью комбинированного ключа: ключ, который представляет собой комбинацию обоих чисел и имен файлов. Напр. для первой записи ключ будет (23, fileA), а не просто (23).

Вы можете прочитать о среднем рода здесь: https://www.safaribooksonline.com/library/view/data-algorithms/9781491906170/ch01.html

Вы также можете пройти в раздел "Secondary Сортировка", в "Hadoop The Definitive Guide" книги.

Для простоты я написал программу для достижения того же.

В этой программе ключи сортируются по умолчанию картографами. Я написал логику для сортировки значений на стороне редуктора. Поэтому он заботится о сортировке как ключей, так и значений и создает желаемый результат.

Ниже приводится программа:

package com.myorg.hadooptests; 

import org.apache.hadoop.conf.Configuration; 
import org.apache.hadoop.fs.Path; 
import org.apache.hadoop.io.*; 
import org.apache.hadoop.mapreduce.Job; 
import org.apache.hadoop.mapreduce.Mapper; 
import org.apache.hadoop.mapreduce.Reducer; 
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; 
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; 

import java.io.IOException; 
import java.util.*; 

public class SortedValue { 


    public static class SortedValueMapper 
      extends Mapper<LongWritable, Text , Text, IntWritable>{ 

     public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { 

      String[] tokens = value.toString().split(" "); 

      if(tokens.length == 2) { 
       context.write(new Text(tokens[1]), new IntWritable(Integer.parseInt(tokens[0]))); 
      } 
     } 
    } 

    public static class SortedValueReducer 
      extends Reducer<Text, IntWritable, IntWritable, Text> { 

     Map<String, ArrayList<Integer>> valueMap = new HashMap<String, ArrayList<Integer>>(); 

     public void reduce(Text key, Iterable<IntWritable> values, 
          Context context) throws IOException, InterruptedException { 

      String keyStr = key.toString(); 
      ArrayList<Integer> storedValues = valueMap.get(keyStr); 

      for (IntWritable value : values) { 
       if (storedValues == null) { 
        storedValues = new ArrayList<Integer>(); 
        valueMap.put(keyStr, storedValues); 
       } 
       storedValues.add(value.get()); 
      } 

      Collections.sort(storedValues); 
      for (Integer val : storedValues) { 
       context.write(new IntWritable(val), key); 
      } 
     } 
    } 

    public static void main(String[] args) throws Exception { 

     Configuration conf = new Configuration(); 

     Job job = Job.getInstance(conf, "CompositeKeyExample"); 
     job.setJarByClass(SortedValue.class); 
     job.setMapperClass(SortedValueMapper.class); 
     job.setReducerClass(SortedValueReducer.class); 

     job.setMapOutputKeyClass(Text.class); 
     job.setMapOutputValueClass(IntWritable.class); 

     job.setOutputKeyClass(IntWritable.class); 
     job.setOutputValueClass(Text.class); 

     FileInputFormat.addInputPath(job, new Path("/in/in1.txt")); 
     FileOutputFormat.setOutputPath(job, new Path("/out/")); 

     System.exit(job.waitForCompletion(true) ? 0:1); 

    } 
} 

Mapper Логика:

  1. Разбираем каждую строку. Предполагается, что ключ и значение разделяются пустым символом ("").
  2. Если строка содержит 2 жетона, она испускает (имя файла, целочисленное значение). Напр. для первой записи он испускает (fileA, 23).

Редуктор Логика:

  1. Это ставит (ключ, значение) пар в HashMap, где ключ это имя файла и значение представляет собой список целых чисел для этого файла. Напр. для файлаA сохраненные значения будут 23, 34 и 35

  2. Наконец, он сортирует значения для определенного ключа и для каждого значения испускает (значение, ключ) из редуктора. Напр. для FiLea, выход записи: (23, FiLea), (34, FiLea) и (35, FiLea)

Я запустил эту программу для следующего входа:

34 fileB 
35 fileA 
60 fileC 
60 fileA 
23 fileA 

я получил следующий результат:

23  fileA 
35  fileA 
60  fileA 
34  fileB 
60  fileC