Xâu chuỗi nhiều công việc MapReduce trong Hadoop


124

Trong nhiều tình huống thực tế khi bạn áp dụng MapReduce, các thuật toán cuối cùng kết thúc là một số bước MapReduce.

tức là Map1, Giảm1, Map2, Giảm2, v.v.

Vì vậy, bạn có đầu ra từ mức giảm cuối cùng cần thiết làm đầu vào cho bản đồ tiếp theo.

Dữ liệu trung gian là thứ bạn (nói chung) không muốn giữ lại khi đường ống đã được hoàn thành thành công. Ngoài ra, vì dữ liệu trung gian này nói chung là một số cấu trúc dữ liệu (như 'bản đồ' hoặc 'bộ'), bạn không muốn mất quá nhiều công sức để viết và đọc các cặp giá trị khóa này.

Cách làm được đề nghị trong Hadoop là gì?

Có một ví dụ (đơn giản) chỉ ra cách xử lý dữ liệu trung gian này theo cách chính xác, bao gồm cả việc dọn dẹp sau đó không?


2
sử dụng khung mapreduce nào?
skaffman

1
Tôi đã chỉnh sửa câu hỏi để làm rõ Tôi đang nói về Hadoop.
Niels Basjes

Tôi muốn giới thiệu loại đá quý dành cho người này: github.com/Ganglion/swineherd , Tobias
Tobias

Câu trả lời:


57

Tôi nghĩ rằng hướng dẫn này trên mạng nhà phát triển của Yahoo sẽ giúp bạn điều này: Chuỗi việc làm

Bạn sử dụng JobClient.runJob(). Đường dẫn đầu ra của dữ liệu từ công việc đầu tiên trở thành đường dẫn đầu vào cho công việc thứ hai của bạn. Chúng cần được truyền vào dưới dạng đối số cho công việc của bạn với mã thích hợp để phân tích chúng và thiết lập các tham số cho công việc.

Tuy nhiên, tôi nghĩ rằng phương pháp trên có thể là cách mà API ánh xạ cũ hơn đã làm, nhưng nó vẫn hoạt động. Sẽ có một phương pháp tương tự trong API mapreduce mới nhưng tôi không chắc nó là gì.

Khi xóa dữ liệu trung gian sau khi hoàn thành công việc, bạn có thể thực hiện việc này trong mã của mình. Cách tôi đã làm trước đây là sử dụng một cái gì đó như:

FileSystem.delete(Path f, boolean recursive);

Trong đó đường dẫn là vị trí trên HDFS của dữ liệu. Bạn cần đảm bảo rằng bạn chỉ xóa dữ liệu này một khi không có công việc nào khác yêu cầu nó.


3
Cảm ơn các liên kết đến hướng dẫn Yahoo. Công việc Chaining thực sự là những gì bạn muốn nếu cả hai cùng chạy. Những gì tôi đang tìm kiếm là cách dễ dàng để làm nếu bạn muốn có thể chạy chúng một cách riêng biệt. Trong hướng dẫn đã đề cập, tôi đã tìm thấy SequenceFileOutputFormat "Viết các tệp nhị phân phù hợp để đọc các công việc MapReduce tiếp theo" và SequenceFileInputFormat phù hợp, điều này rất dễ thực hiện. Cảm ơn.
Niels Basjes

20

Có nhiều cách bạn có thể làm điều đó.

(1) Công việc xếp tầng

Tạo đối tượng JobConf "job1" cho công việc đầu tiên và đặt tất cả các tham số với "input" là inputdirectory và "temp" làm thư mục đầu ra. Thực hiện công việc này:

JobClient.run(job1).

Ngay bên dưới nó, tạo đối tượng JobConf "job2" cho công việc thứ hai và đặt tất cả các tham số với "temp" làm thư mục đầu vào và "đầu ra" làm thư mục đầu ra. Thực hiện công việc này:

JobClient.run(job2).

(2) Tạo hai đối tượng JobConf và đặt tất cả các tham số trong chúng giống như (1) ngoại trừ việc bạn không sử dụng JobClient.run.

Sau đó tạo hai đối tượng Công việc với jobconfs làm tham số:

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

Sử dụng đối tượng jobControl, bạn chỉ định các phụ thuộc công việc và sau đó chạy các công việc:

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

(3) Nếu bạn cần một cấu trúc hơi giống Map + | Giảm | Bản đồ *, bạn có thể sử dụng các lớp ChainMapper và ChainReducer đi kèm với phiên bản Hadoop 0.19 trở đi.


7

Thực tế có một số cách để làm điều này. Tôi sẽ tập trung vào hai.

Một là thông qua Riffle ( http://github.com/cwensel/riffle ) một thư viện chú thích để xác định những thứ phụ thuộc và 'thực thi' chúng theo thứ tự phụ thuộc (topo).

Hoặc bạn có thể sử dụng Cascade (và MapReduceFlow) trong Cascading ( http://www.cascading.org/ ). Một phiên bản trong tương lai sẽ hỗ trợ các chú thích Riffle, nhưng hiện tại nó hoạt động rất tốt với các công việc MR JobConf thô.

Một biến thể của điều này là hoàn toàn không quản lý các công việc MR, mà là phát triển ứng dụng của bạn bằng API Cascading. Sau đó, JobConf và chuỗi công việc được xử lý nội bộ thông qua các lớp Flow và trình lập kế hoạch Cascading.

Bằng cách này, bạn dành thời gian tập trung vào vấn đề của mình, chứ không phải cơ chế quản lý công việc Hadoop, v.v. Bạn thậm chí có thể xếp các ngôn ngữ khác nhau lên trên (như clojure hoặc jruby) để đơn giản hóa hơn nữa việc phát triển và ứng dụng của bạn. http://www.cascading.org/modules.html


6

Tôi đã thực hiện chuỗi công việc bằng cách sử dụng các đối tượng JobConf lần lượt. Tôi lấy ví dụ WordCount để xâu chuỗi các công việc. Một công việc chỉ ra số lần một từ lặp đi lặp lại trong đầu ra đã cho. Công việc thứ hai lấy đầu ra công việc đầu tiên làm đầu vào và tìm ra tổng số từ trong đầu vào đã cho. Dưới đây là mã cần được đặt trong lớp Driver.

    //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);

Lệnh để chạy các công việc này là:

bin / hadoop jar Totalemme.

Chúng ta cần đặt tên công việc cuối cùng cho lệnh. Trong trường hợp trên, đó là Totalemme.


5

Bạn có thể chạy chuỗi MR theo cách được đưa ra trong mã.

XIN LƯU Ý : Chỉ mã trình điều khiển đã được cung cấp

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);
      }

}

BẢN ĐỒ TÌM KIẾM LÀ

( CÔNG VIỆC ) -> GIẢM -> ( JOB2 )
Điều này được thực hiện để lấy các khóa được sắp xếp nhưng vẫn có nhiều cách khác như sử dụng bản đồ tre
Tuy nhiên tôi muốn tập trung sự chú ý của bạn vào cách mà Công việc đã bị xiềng xích! !
Cảm ơn bạn




3

Chúng ta có thể sử dụng waitForCompletion(true)phương pháp của Công việc để xác định sự phụ thuộc giữa các công việc.

Trong kịch bản của tôi, tôi đã có 3 công việc phụ thuộc lẫn nhau. Trong lớp trình điều khiển tôi đã sử dụng mã dưới đây và nó hoạt động như mong đợi.

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=================");
                }
            }
        }
    }

Câu trả lời của bạn là về cách tham gia các công việc này về mặt thực thi. Câu hỏi ban đầu là về các cơ sở dữ liệu tốt nhất. Vì vậy, câu trả lời của bạn không liên quan đến câu hỏi cụ thể này.
Niels Basjes

2

Class mới org.apache.hadoop.mapreduce.lib.chain.ChainMapper giúp kịch bản này


1
Câu trả lời là tốt - nhưng bạn nên thêm một số chi tiết về những gì nó làm hoặc ít nhất là một liên kết đến tham chiếu API để mọi người có thể bình chọn
Jeremy Hajek

ChainMapper và ChainReducer được sử dụng để có 1 hoặc nhiều trình ánh xạ trước Giảm và 0 hoặc nhiều trình ánh xạ sau Giảm, thông số kỹ thuật. (Mapper +) Giảm (Mapper *). Sửa lỗi cho tôi nếu tôi sai rõ ràng nhưng tôi không nghĩ cách tiếp cận này hoàn thành việc xâu chuỗi các công việc như OP yêu cầu.
oczkoisse

1

Mặc dù có các công cụ dòng công việc Hadoop dựa trên máy chủ phức tạp, ví dụ oozie, tôi có một thư viện java đơn giản cho phép thực thi nhiều công việc Hadoop như một quy trình công việc. Cấu hình công việc và quy trình công việc xác định phụ thuộc công việc liên được cấu hình trong tệp JSON. Mọi thứ đều có thể cấu hình bên ngoài và không yêu cầu bất kỳ thay đổi nào trong bản đồ hiện tại làm giảm việc thực hiện là một phần của quy trình công việc.

Thông tin chi tiết có thể được tìm thấy ở đây. Mã nguồn và jar có sẵn trong github.

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

Pranab


1

Tôi nghĩ oozie giúp các công việc tiếp theo nhận được đầu vào trực tiếp từ công việc trước đó. Điều này tránh hoạt động I / o được thực hiện với jobcontrol.


1

Nếu bạn muốn lập trình chuỗi các công việc của mình, bạn sẽ sử dụng JobControl. Cách sử dụng khá đơn giản:

JobControl jobControl = new JobControl(name);

Sau đó, bạn thêm các trường hợp ControledJob. ControledJob định nghĩa một công việc với các phụ thuộc của nó, do đó tự động cắm đầu vào và đầu ra để phù hợp với "chuỗi" công việc.

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

    jobControl.run();

bắt đầu chuỗi Bạn sẽ muốn đặt nó trong một chủ đề speerate. Điều này cho phép kiểm tra trạng thái chuỗi của bạn khi nó chạy:

    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

Như bạn đã đề cập trong yêu cầu của bạn rằng bạn muốn o / p của MRJob1 là i / p của MRJob2, v.v., bạn có thể xem xét sử dụng quy trình làm việc oozie cho usecase này. Ngoài ra, bạn có thể xem xét việc ghi dữ liệu trung gian của mình lên HDFS vì nó sẽ được sử dụng bởi MRJob tiếp theo. Và sau khi công việc hoàn thành, bạn có thể dọn sạch dữ liệu trung gian của mình.

<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"/>

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.