Как управлять объединениями в hadoop - MultipleInputPath

1

После того, как сторона карты присоединится к данным, которые я получаю в Редукторе,

key------ book
values
    6
    eraser=>book 2
    pen=>book 4
    pencil=>book 5

То, что я в основном хочу сделать, это

eraser=>book = 2/6
pen=>book = 4/6
pencil=>book = 5/6

То, что я изначально сделал,

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

        System.out.println("key------ "+key);
        System.out.println("Values");
        for(Text value : values){
            System.out.println("\t"+value.toString());
            String v = value.toString();
            double BsupportCnt = 0;
            double UsupportCnt = 0;
            double res = 0;
            if(!v.contains("=>")){
                BsupportCnt = Double.parseDouble(v);
            }
            else{
                String parts[] = v.split(" ");
                UsupportCnt = Double.parseDouble(parts[1]);
            }
//          calculate here
            res = UsupportCnt/BsupportCnt;

        }

Если входящие данные имеют значение выше, это работает отлично

Но если входящие данные из mapper

key------ book
values
    eraser=>book 2
    pen=>book 4
    pencil=>book 5
    6

Это не работает. Или мне нужно сохранить все => в списке (если входящие данные представляют собой большие данные, список может попасть в область Heap), и как только я получу номер, я должен выполнить расчет.

ОБНОВЛЕНИЕ Когда Vefthym попросил вторичную сортировку значений до того, как он достигнет редуктора. Я использовал htuple чтобы сделать то же самое. Я добавил эту ссылку

В mapper1 испускает eraser=>book 2 as value So

public class AprioriItemMapper1 extends Mapper<Text, Text, Text, Tuple>{
    public void map(Text key,Text value,Context context) throws IOException, InterruptedException{
        //Configurations and other stuffs
        //allWords is an ArrayList
        if(allWords.size()<=2)
        {
            Tuple outputKey = new Tuple();
            String LHS1 = allWords.get(1);
            String RHS1 = allWords.get(0)+"=>"+allWords.get(1)+" "+value.toString();
            outputKey.set(TupleFields.ALPHA, RHS1);
            context.write(new Text(LHS1), outputKey);
                 }
//other stuffs

Mapper2 испускает numbers как значение

public class AprioriItemMapper2 extends Mapper<Text, Text, Text, Tuple>{
    Text valEmit = new Text(); 
    public void map(Text key,Text value,Context context) throws IOException, InterruptedException{
        //Configuration and other stuffs
        if(cnt != supCnt && cnt < supCnt){
            System.out.println("emit");
            Tuple outputKey = new Tuple();
            outputKey.set(TupleFields.NUMBER, value);

            System.out.println("v---"+value);
            System.out.println("outputKey.toString()---"+outputKey.toString());
            context.write(key, outputKey);
        }

Редуктор Я просто пытался распечатать ключ и значения

Но эта ошибка

Mapper 2: 
line book
Support Count: 2
count--- 1
emit
v---6
outputKey.toString()---[0]='6, 
14/08/07 13:54:19 INFO mapred.LocalJobRunner: Map task executor complete.
14/08/07 13:54:19 WARN mapred.LocalJobRunner: job_local626380383_0003
java.lang.Exception: java.lang.ClassCastException: org.apache.hadoop.io.Text cannot be cast to org.htuple.Tuple
    at org.apache.hadoop.mapred.LocalJobRunner$Job.run(LocalJobRunner.java:406)
Caused by: java.lang.ClassCastException: org.apache.hadoop.io.Text cannot be cast to org.htuple.Tuple
    at org.htuple.TupleMapReducePartitioner.getPartition(TupleMapReducePartitioner.java:28)
    at org.apache.hadoop.mapred.MapTask$NewOutputCollector.write(MapTask.java:601)
    at org.apache.hadoop.mapreduce.task.TaskInputOutputContextImpl.write(TaskInputOutputContextImpl.java:85)
    at org.apache.hadoop.mapreduce.lib.map.WrappedMapper$Context.write(WrappedMapper.java:106)
    at edu.am.bigdata.apriori.AprioriItemMapper1.map(AprioriItemMapper1.java:49)
    at edu.am.bigdata.apriori.AprioriItemMapper1.map(AprioriItemMapper1.java:1)
    at org.apache.hadoop.mapreduce.Mapper.run(Mapper.java:140)
    at org.apache.hadoop.mapreduce.lib.input.DelegatingMapper.run(DelegatingMapper.java:51)
    at org.apache.hadoop.mapred.MapTask.runNewMapper(MapTask.java:672)
    at org.apache.hadoop.mapred.MapTask.run(MapTask.java:330)
    at org.apache.hadoop.mapred.LocalJobRunner$Job$MapTaskRunnable.run(LocalJobRunner.java:268)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
    at java.util.concurrent.FutureTask.run(FutureTask.java:166)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:722)

Err находится в context.write(new Text(LHS1), outputKey); от AprioriItemMapper1.java:49 но вышеприведенные данные печати взяты из Mapper 2

Любой лучший способ сделать это Пожалуйста, предложите.

  • 0
    откуда 6? Может ли это быть частью ключа? Что вы делаете с res после того, как он вычислен?
  • 0
    Вторичная сортировка (сортировка входных данных редуктора по значению) может помочь вам гарантировать, что первое значение будет BsupportCnt , поскольку число лексикографически меньше любой буквы.
Показать ещё 6 комментариев
Теги:
hadoop
join
mapreduce

1 ответ

0

Я бы предложил использовать вторичную сортировку, которая гарантировала бы, что первое значение (отсортированное лексикографически) является числовым, если нет слов, начинающихся с числа.

Если это не сработает, то с учетом ограничений масштабируемости, которые вы упомянули, я бы сохранил значения редуктора в буфере HashMap<String,Double> а ключи - левые части "=>", а значения - их числовые значения. Вы можете сохранить значения, пока не получите значение знаменателя BsupportCnt. Затем вы можете испускать все содержимое буфера с правильным счетом и всеми остальными значениями, поскольку они появляются один за другим, без необходимости снова использовать буфер (поскольку теперь вы знаете знаменатель). Что-то вроде того:

public void reduce(Text key,Iterable<Text> values , Context context) throws IOException, InterruptedException{
    Map<String,Double> buffer = new HashMap<>();
    double BsupportCnt = 0;
    double UsupportCnt;
    double res;
    for(Text value : values){
        String v = value.toString();

        if(!v.contains("=>")){
            BsupportCnt = Double.parseDouble(v);
        } else {
            String parts[] = v.split(" ");
            UsupportCnt = Double.parseDouble(parts[1]);

            if (BsupportCnt != 0) { //no need to add things to the buffer any more
               res = UsupportCnt/BsupportCnt;
               context.write(new Text(v), new DoubleWritable(res));
            } else {
               buffer.put(parts[0], UsupportCnt);
            }
        }

    }


    //now emit the buffer contents
    for (Map<String,Double>.Entry entry : buffer) {
        context.write(new Text(entry.getKey()), new DoubleWritable(entry.getValue()/BsupportCnt));
    }
}

Вы могли бы получить больше места, сохранив только левую часть "=>" в качестве клавиш HashMap, так как правая часть всегда является ключом ввода редуктора.

  • 0
    vefthym, еще одно сомнение - этот буфер может также захватывать пространство кучи? Поправьте меня если я не прав
  • 1
    Исправьте, если значения соблюдены, пока нахождение знаменателя не станет больше размера кучи.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню