Hadoop'ta birden fazla MapReduce işi zincirleme


124

MapReduce'u uyguladığınız birçok gerçek yaşam durumunda, son algoritmalar birkaç MapReduce adımı olur.

ör. Map1, Reduce1, Map2, Reduce2 vb.

Böylece, bir sonraki harita için girdi olarak gerekli olan son azaltmanın çıktısına sahip olursunuz.

Ara veriler, ardışık düzen başarıyla tamamlandıktan sonra (genel olarak) saklamak istemediğiniz bir şeydir. Ayrıca bu ara veriler genel olarak bazı veri yapıları olduğundan (bir 'harita' veya 'küme' gibi) bu anahtar / değer çiftlerini yazmak ve okumak için çok fazla çaba harcamak istemezsiniz.

Hadoop'ta bunu yapmanın önerilen yolu nedir?

Bu ara verilerin nasıl doğru şekilde işleneceğini gösteren (daha sonra temizleme dahil) (basit) bir örnek var mı?


2
hangi mapreduce çerçevesini kullanıyorsunuz?
skaffman

1
Hadoop'tan bahsettiğimi açıklığa kavuşturmak için soruyu düzenledim.
Niels Basjes

Bunun için domuz çobanını tavsiye ederim: github.com/Ganglion/swineherd best, Tobias
Tobias

Yanıtlar:


57

Yahoo'nun geliştirici ağındaki bu öğreticinin size bu konuda yardımcı olacağını düşünüyorum: Zincirleme İşleri

Sen kullanabilirsiniz JobClient.runJob(). İlk işten gelen verilerin çıktı yolu, ikinci işinizin giriş yolu olur. Bunların, ayrıştırmak ve iş için parametreleri ayarlamak için uygun kodla işlerinize bağımsız değişkenler olarak aktarılması gerekir.

Ancak, yukarıdaki yöntemin, şimdi daha eski olan mapred API'nin yaptığı gibi olabileceğini düşünüyorum, ancak yine de çalışmalıdır. Yeni mapreduce API'de de benzer bir yöntem olacak, ancak ne olduğundan emin değilim.

Bir iş bittikten sonra ara verileri kaldırmakla ilgili olarak, bunu kodunuzda yapabilirsiniz. Bunu daha önce yaptığım yöntem şuna benzer bir şey kullanmaktı:

FileSystem.delete(Path f, boolean recursive);

Yol, verilerin HDFS'sindeki konumdur. Bu verileri yalnızca başka hiçbir iş gerektirmediğinde sildiğinizden emin olmanız gerekir.


3
Yahoo eğitimine bağlantı için teşekkürler. Zincirleme İşleri, eğer ikisi aynı koşudaysa gerçekten istediğiniz şeydir. Aradığım şey, onları ayrı ayrı çalıştırabilmek istiyorsanız yapmanın kolay yoluydu. Bahsedilen eğiticide, SequenceFileOutputFormat "Sonraki MapReduce işlerini okumak için uygun ikili dosyalar yazar" ve hepsini yapmayı çok kolaylaştıran eşleşen SequenceFileInputFormat buldum. Teşekkürler.
Niels Basjes

20

Bunu yapmanın birçok yolu var.

(1) Basamaklı işler

İlk iş için JobConf nesnesi "job1" oluşturun ve tüm parametreleri girdi dizini olarak "input" ve çıktı dizini olarak "temp" ile ayarlayın. Bu işi yürütün:

JobClient.run(job1).

Hemen altında, ikinci iş için "job2" JobConf nesnesini oluşturun ve tüm parametreleri "temp" ile inputdizini ve "output" çıkış dizini olarak ayarlayın. Bu işi yürütün:

JobClient.run(job2).

(2) İki JobConf nesnesi oluşturun ve bunlardaki tüm parametreleri, JobClient.run kullanmamanız dışında aynı (1) gibi ayarlayın.

Ardından, parametre olarak jobconfs ile iki Job nesnesi oluşturun:

Job job1=new Job(jobconf1); 
Job job2=new Job(jobconf2);

JobControl nesnesini kullanarak iş bağımlılıklarını belirler ve ardından işleri çalıştırırsınız:

JobControl jbcntrl=new JobControl("jbcntrl");
jbcntrl.addJob(job1);
jbcntrl.addJob(job2);
job2.addDependingJob(job1);
jbcntrl.run();

(3) Map + gibi bir yapıya ihtiyacınız varsa | Azalt | Map *, Hadoop sürüm 0.19 ve sonrası ile birlikte gelen ChainMapper ve ChainReducer sınıflarını kullanabilirsiniz.


7

Aslında bunu yapmanın birkaç yolu var. Ben ikiye odaklanacağım.

Biri Riffle ( http://github.com/cwensel/riffle ) aracılığıyla, bağımlı şeyleri tanımlamak ve bunları bağımlılık (topolojik) sırayla 'yürütmek' için bir açıklama kitaplığıdır.

Veya Cascade'de ( http://www.cascading.org/ ) Cascade (ve MapReduceFlow) kullanabilirsiniz . Gelecekteki bir sürüm, Riffle açıklamalarını destekleyecek, ancak şu anda ham MR JobConf işleriyle harika çalışıyor.

Bunun bir varyantı, MR işlerini elle yönetmek değil, Cascading API kullanarak uygulamanızı geliştirmektir. Ardından JobConf ve iş zinciri, Basamaklı planlayıcı ve Akış sınıfları aracılığıyla dahili olarak ele alınır.

Bu şekilde, zamanınızı Hadoop işlerini yönetme mekaniğine değil, probleminize odaklanarak harcarsınız. Geliştirme ve uygulamalarınızı daha da basitleştirmek için farklı dilleri (clojure veya jruby gibi) üstte katmanlara ayırabilirsiniz. http://www.cascading.org/modules.html


6

JobConf nesnelerini birbiri ardına kullanarak iş zincirleme yaptım. İşleri zincirlemek için WordCount örneğini aldım. Bir iş, verilen çıktıda bir kelimenin kaç kez tekrarlandığını hesaplar. İkinci iş girdi olarak ilk iş çıktısını alır ve verilen girdideki toplam kelimeleri hesaplar. Driver sınıfına yerleştirilmesi gereken kod aşağıdadır.

    //First Job - Counts, how many times a word encountered in a given file 
    JobConf job1 = new JobConf(WordCount.class);
    job1.setJobName("WordCount");

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

    job1.setMapperClass(WordCountMapper.class);
    job1.setCombinerClass(WordCountReducer.class);
    job1.setReducerClass(WordCountReducer.class);

    job1.setInputFormat(TextInputFormat.class);
    job1.setOutputFormat(TextOutputFormat.class);

    //Ensure that a folder with the "input_data" exists on HDFS and contains the input files
    FileInputFormat.setInputPaths(job1, new Path("input_data"));

    //"first_job_output" contains data that how many times a word occurred in the given file
    //This will be the input to the second job. For second job, input data name should be
    //"first_job_output". 
    FileOutputFormat.setOutputPath(job1, new Path("first_job_output"));

    JobClient.runJob(job1);


    //Second Job - Counts total number of words in a given file

    JobConf job2 = new JobConf(TotalWords.class);
    job2.setJobName("TotalWords");

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

    job2.setMapperClass(TotalWordsMapper.class);
    job2.setCombinerClass(TotalWordsReducer.class);
    job2.setReducerClass(TotalWordsReducer.class);

    job2.setInputFormat(TextInputFormat.class);
    job2.setOutputFormat(TextOutputFormat.class);

    //Path name for this job should match first job's output path name
    FileInputFormat.setInputPaths(job2, new Path("first_job_output"));

    //This will contain the final output. If you want to send this jobs output
    //as input to third job, then third jobs input path name should be "second_job_output"
    //In this way, jobs can be chained, sending output one to other as input and get the
    //final output
    FileOutputFormat.setOutputPath(job2, new Path("second_job_output"));

    JobClient.runJob(job2);

Bu işleri çalıştırma komutu:

bin / hadoop jar TotalWords.

Komut için son işlerin adını vermemiz gerekiyor. Yukarıdaki durumda, TotalWords'tür.


5

MR zincirini kodda verilen şekilde çalıştırabilirsiniz.

LÜTFEN DİKKAT : Yalnızca sürücü kodu sağlanmıştır

public class WordCountSorting {
// here the word keys shall be sorted
      //let us write the wordcount logic first

      public static void main(String[] args)throws IOException,InterruptedException,ClassNotFoundException {
            //THE DRIVER CODE FOR MR CHAIN
            Configuration conf1=new Configuration();
            Job j1=Job.getInstance(conf1);
            j1.setJarByClass(WordCountSorting.class);
            j1.setMapperClass(MyMapper.class);
            j1.setReducerClass(MyReducer.class);

            j1.setMapOutputKeyClass(Text.class);
            j1.setMapOutputValueClass(IntWritable.class);
            j1.setOutputKeyClass(LongWritable.class);
            j1.setOutputValueClass(Text.class);
            Path outputPath=new Path("FirstMapper");
            FileInputFormat.addInputPath(j1,new Path(args[0]));
                  FileOutputFormat.setOutputPath(j1,outputPath);
                  outputPath.getFileSystem(conf1).delete(outputPath);
            j1.waitForCompletion(true);
                  Configuration conf2=new Configuration();
                  Job j2=Job.getInstance(conf2);
                  j2.setJarByClass(WordCountSorting.class);
                  j2.setMapperClass(MyMapper2.class);
                  j2.setNumReduceTasks(0);
                  j2.setOutputKeyClass(Text.class);
                  j2.setOutputValueClass(IntWritable.class);
                  Path outputPath1=new Path(args[1]);
                  FileInputFormat.addInputPath(j2, outputPath);
                  FileOutputFormat.setOutputPath(j2, outputPath1);
                  outputPath1.getFileSystem(conf2).delete(outputPath1, true);
                  System.exit(j2.waitForCompletion(true)?0:1);
      }

}

SIRA IS

( JOB1 ) Harita-> REDUCE-> ( job2 ) MAP
Bu tuşlar orada böyle bir treemap kullanma gibi daha yararlanabilirsiniz henüz sıralanmış almak yapıldı
Yine de İşler zincirleme edilme yöntemlerine üzerine dikkatinizi odaklanmak istiyorum! !
teşekkür ederim




3

waitForCompletion(true)İş arasındaki bağımlılığı tanımlamak için İşin yöntemini kullanabiliriz .

Benim senaryomda birbirine bağlı 3 işim vardı. Sürücü sınıfında aşağıdaki kodu kullandım ve beklendiği gibi çalışıyor.

public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub

        CCJobExecution ccJobExecution = new CCJobExecution();

        Job distanceTimeFraudJob = ccJobExecution.configureDistanceTimeFraud(new Configuration(),args[0], args[1]);
        Job spendingFraudJob = ccJobExecution.configureSpendingFraud(new Configuration(),args[0], args[1]);
        Job locationFraudJob = ccJobExecution.configureLocationFraud(new Configuration(),args[0], args[1]);

        System.out.println("****************Started Executing distanceTimeFraudJob ================");
        distanceTimeFraudJob.submit();
        if(distanceTimeFraudJob.waitForCompletion(true))
        {
            System.out.println("=================Completed DistanceTimeFraudJob================= ");
            System.out.println("=================Started Executing spendingFraudJob ================");
            spendingFraudJob.submit();
            if(spendingFraudJob.waitForCompletion(true))
            {
                System.out.println("=================Completed spendingFraudJob================= ");
                System.out.println("=================Started locationFraudJob================= ");
                locationFraudJob.submit();
                if(locationFraudJob.waitForCompletion(true))
                {
                    System.out.println("=================Completed locationFraudJob=================");
                }
            }
        }
    }

Cevabınız, icra açısından bu işlere nasıl katılacağınız ile ilgili. Asıl soru, en iyi veri yapıları hakkındaydı. Yani cevabınız bu spesifik soruyla alakalı değil.
Niels Basjes

2

Yeni Sınıf org.apache.hadoop.mapreduce.lib.chain.ChainMapper bu senaryoya yardımcı olur


1
Cevap güzel - ancak ne yaptığı hakkında biraz daha ayrıntı veya en azından insanların
olumlu

ChainMapper ve ChainReducer, Reduce'tan önce 1 veya daha fazla eşleyiciye ve Reduce, spec'den sonra 0 veya daha fazla eşleyiciye sahip olmak için kullanılır. (Eşleyici +) Azalt (Eşleyici *). Açıkçası yanılıyorsam düzeltin ama bu yaklaşımın, OP'nin istediği gibi işleri seri bir şekilde zincirlemeyi başaracağını düşünmüyorum.
oczkoisse

1

Oozie gibi karmaşık sunucu tabanlı Hadoop iş akışı motorları olmasına rağmen, bir iş akışı olarak birden çok Hadoop işinin yürütülmesini sağlayan basit bir java kitaplığım var. İşler arası bağımlılığı tanımlayan iş yapılandırması ve iş akışı bir JSON dosyasında yapılandırılır. Her şey harici olarak yapılandırılabilir ve mevcut haritada herhangi bir değişiklik gerektirmez, uygulamayı bir iş akışının parçası haline getirir.

Detaylar burada bulunabilir. Kaynak kodu ve jar, github'da mevcuttur.

http://pkghosh.wordpress.com/2011/05/22/hadoop-orchestration/

Pranab


1

Bence oozie, sonuçta ortaya çıkan işlerin girdileri doğrudan önceki işten almasına yardımcı oluyor. Bu, jobcontrol ile gerçekleştirilen G / Ç işlemini önler.


1

İşlerinizi programlı olarak zincirlemek istiyorsanız, JobControl'ü kullanmak isteyeceksiniz. Kullanım oldukça basittir:

JobControl jobControl = new JobControl(name);

Bundan sonra ControlledJob örneklerini eklersiniz. ControlledJob, bağımlılıkları olan bir işi tanımlar, böylece girdileri ve çıktıları bir iş "zincirine" uyacak şekilde otomatik olarak takar.

    jobControl.add(new ControlledJob(job, Arrays.asList(controlledjob1, controlledjob2));

    jobControl.run();

zinciri başlatır. Bunu ayrı bir konuya sokmak isteyeceksiniz. Bu, zinciriniz çalışırken durumunu kontrol etmenizi sağlar:

    while (!jobControl.allFinished()) {
        System.out.println("Jobs in waiting state: " + jobControl.getWaitingJobList().size());
        System.out.println("Jobs in ready state: " + jobControl.getReadyJobsList().size());
        System.out.println("Jobs in running state: " + jobControl.getRunningJobList().size());
        List<ControlledJob> successfulJobList = jobControl.getSuccessfulJobList();
        System.out.println("Jobs in success state: " + successfulJobList.size());
        List<ControlledJob> failedJobList = jobControl.getFailedJobList();
        System.out.println("Jobs in failed state: " + failedJobList.size());
    }

0

MRJob1'in o / p'sinin MRJob2'nin i / p'si olmasını istediğiniz gereksiniminizde belirttiğiniz gibi, bu kullanım alanı için oozie iş akışını kullanmayı düşünebilirsiniz. Ayrıca, sonraki MRJob tarafından kullanılacağından, ara verilerinizi HDFS'ye yazmayı da düşünebilirsiniz. Ve iş tamamlandıktan sonra ara verilerinizi temizleyebilirsiniz.

<start to="mr-action1"/>
<action name="mr-action1">
   <!-- action for MRJob1-->
   <!-- set output path = /tmp/intermediate/mr1-->
    <ok to="end"/>
    <error to="end"/>
</action>

<action name="mr-action2">
   <!-- action for MRJob2-->
   <!-- set input path = /tmp/intermediate/mr1-->
    <ok to="end"/>
    <error to="end"/>
</action>

<action name="success">
        <!-- action for success-->
    <ok to="end"/>
    <error to="end"/>
</action>

<action name="fail">
        <!-- action for fail-->
    <ok to="end"/>
    <error to="end"/>
</action>

<end name="end"/>

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.