Workshop Hadoop MapReduce
WordCount v1.0 Source Code
You
versions
at http://tiny.cloudera.com/hadoopTutorialSample. This
summarizes the code for WordCount version 1.0.
source
three
code
find
can
for
of WordCount
topic examines and
You can use an appropriate package for your domain, or keep the generic version.
package org.myorg;
only
The
import
are IOException and regex.Pattern. You use regex.Pattern to extract words from
input files.
standard
classes
need
Java
you
to
import java.io.IOException;
import java.util.regex.Pattern;
This application extends the class Configured, and implements the Tool utility class.
You tell Hadoop what it needs to know to run your program in a configuration
object. Then, you use ToolRunner to run your MapReduce application.
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
The Logger class sends debugging messages from inside the mapper and reducer
classes. When you run the application, one of the standard INFO messages provides
Publicité
a URL you can use to track the job's success. Messages you pass to Logger are
displayed in the map or reduce logs for the job on your Hadoop server.
import org.apache.log4j.Logger;
You need the Job class to create, configure, and run an instance of your MapReduce
application. You extend the Mapper class with your own Mapclass and add your own
processing instructions. The same is true for the Reducer: you extend it to create
and customize your own Reduce class.
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
Use the Path class to access files in HDFS. In your job configuration instructions,
you pass required paths using the FileInputFormat and FileOutputFormat classes.
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
Writable objects have convenience methods for writing, reading, and comparing
values during map and reduce processing. You can think of the Text class
as StringWritable, because it performs essentially the same functions as those for
integer (IntWritable) and long integer (LongWritable) objects.
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
WordCount includes main and run methods, and the inner classes Map andReduce. The
class begins by initializing the logger.
public class WordCount extends Configured implements Tool {
private static final Logger LOG = Logger.getLogger(WordCount.class);
The main method invokes ToolRunner, which creates and runs a new instance
of WordCount, passing the command line arguments. When the application is
finished, it returns an integer value for the status, which is passed to
the System object on exit.
public static void main(String[] args) throws Exception {
int res = ToolRunner.run(new WordCount(), args);
System.exit(res);
}
The run method configures the job (which includes setting paths passed in at the
command line), starts the job, waits for the job to complete, and then returns an
integer value as the success flag.
Publicité
public int run(String[] args) throws Exception {
a
new
uses
Create
the Configured.getConf() method to get the configuration object for this instance
of WordCount, and names the job object wordcount.
the Job object.
example
instance
This
of
Job job = Job.getInstance(getConf(), "wordcount");
Set the JAR to use, based on the class in use.
job.setJarByClass(this.getClass());
Set the input and output paths for your application. You store your input files in
HDFS, and then pass the input and output paths as command-line arguments at
runtime.
FileInputFormat.addInputPaths(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
the map class and reduce class for
Set
the Map and Reduce inner classes defined in this class.
the
job. In
this case, use
job.setMapperClass(Map.class);
job.setReducerClass(Reduce.class);
Use a Text object to output the key (in this case, the word being counted) and the
value (in this case, the number of times the word appears).
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
the
job
and wait
Launch
syntax
Publicité
it
iswaitForCompletion(boolean verbose). When true, the method reports its progress
as the Map and Reduce classes run. When false, the method reports progress up to,
but not including, the Map and Reduce processes.
finish. The method
for
to
In Unix, 0 indicates success, and anything other than 0 indicates a failure. When the
job completes successfully, the method returns 0. When it fails, it returns 1.
return job.waitForCompletion(true) ? 0 : 1;
}
The Map class (an extension of Mapper) transforms key/value input into intermediate
key/value pairs to be sent to the Reducer. The class defines several global variables,
starting with an IntWritable for the value 1, and a Text object used to store each
word as it is parsed from the input string.
public static class Map extends Mapper<LongWritable, Text, Text,
IntWritable> {
private final static IntWritable one = new IntWritable(1);
private Text word = new Text();
Create a regular expression pattern you can use to parse each line of input text on
word boundaries ("\b"). Word boundaries include spaces, tabs, and punctuation.
private
Pattern.compile("\\s\\b\\s");
static
final
Pattern
WORD_BOUNDARY
=
Hadoop invokes the map method once for every key/value pair from your input
source. This does not necessarily correspond to the intermediate key/value pairs
output to the reducer. In this case, the map method receives the offset of the first
character in the current line of input as the key, and a Text object representing an
entire line of text from the input file as the value. It further parses the words on the
line to create the intermediate output.
public void map(LongWritable offset, Text lineText, Context context)
throws IOException, InterruptedException {
Convert the Text object to a string. Create the currentWord variable, which you use
Publicité
to capture individual words from each input string.
String line = lineText.toString();
Text currentWord = new Text();
Use the regular expression pattern to split the line into individual words based on
word boundaries. If the word object is empty (for example, consists of white
space), go to the next parsed object. Otherwise, write a key/value pair to the context
object for the job.
for ( String word : WORD_BOUNDARY.split(line)) {
if (word.isEmpty()) {
continue;
}
currentWord = new Text(word);
context.write(currentWord,one);
}
}
The mapper creates a key/value pair for each word, composed of the word and
the IntWritable value 1. The reducer processes each pair, adding one to the count
for the current word in the key/value pair to the overall count of that word from all
mappers. It then writes the result for that word to the reducer context object, and
moves on to the next. When all of the intermediate key/value pairs are processed,
the map/reduce task is complete. The application saves the results to the output
location in HDFS.
public static class Reduce extends Reducer<Text, IntWritable, Text,
IntWritable> {
@Override public void reduce(Text word, Iterable<IntWritable> counts,
Context context)
throws IOException, InterruptedException {
int sum = 0;
for (IntWritable count : counts) {
sum += count.get();
}
context.write(word, new IntWritable(sum));
}
}
}