
In this tutorial I will describe how to write a simpleMapReduce program for Hadoop in thePython programming
language.
Motivation
Even though the Hadoop framework is written in Java, programs for Hadoop need not to be coded in Java but can also bedeveloped in other languages like Python or C++ (the latter since version 0.14.1). However,Hadoop’s
documentation and the most prominentPython example on the Hadoop website could make you think that youmust translate your Python code using
Jython into a Java jar file. Obviously, this is notvery convenient and can even be problematic if you depend on Python features not provided by Jython. Another issue ofthe Jython approach is the overhead
of writing your Python program in such a way that it can interact with Hadoop –just have a look at the example in$HADOOP_HOME/src/examples/python/WordCount.py
and you see what I mean.
That said, the ground is now prepared for the purpose of this tutorial: writing a Hadoop MapReduce program in a morePythonic way, i.e. in a way you should be familiar with.
What we want to do
We will write a simple MapReduce program (see also theMapReduce article on Wikipedia) for Hadoop in Python but
without usingJython to translate our code to Java jar files.
Our program will mimick the WordCount, i.e. it reads text files andcounts how often words occur. The input is text files and the output is text files, each line of which contains aword and the count of how often it occured, separated by a tab.
Prerequisites
You should have an Hadoop cluster up and running because we will get our hands dirty. If you don’t have a clusteryet, my following tutorials might help you to build one. The tutorials are tailored to Ubuntu Linux but the informationdoes also apply to other
Linux/Unix variants.
-
Running Hadoop On Ubuntu Linux (Single-Node Cluster)– How to set up a pseudo-distributed,
single-node Hadoop cluster backed by the Hadoop Distributed File System(HDFS) -
Running Hadoop On Ubuntu Linux (Multi-Node Cluster)– How to set up a distributed,
multi-node Hadoop cluster backed by the Hadoop Distributed File System(HDFS)
Python MapReduce Code
The “trick” behind the following Python code is that we will use theHadoop Streaming API (see also the correspondingwiki
entry) for helping us passing data between our Map and Reducecode via
(standard input) and
STDINSTDOUT
(standard output). We will simply use Python’s sys.stdin
toread input data and print our own output to sys.stdout
. That’s all we need to do because Hadoop Streaming willtake care
of everything else!
Map step: mapper.py
Save the following code in the file /home/hduser/mapper.py
. It will read data fromSTDIN
, split it into wordsand output a list of lines mapping words to their (intermediate) counts toSTDOUT
. The Map script will notcompute an (intermediate) sum of a word’s occurrences though. Instead, it will output<word> 1
tuples immediately– even though a specific word might occur multiple times in the input. In our case we let the subsequent Reducestep do the final sum count. Of course, you can change this behavior in your own scripts as you please, but
we willkeep it like that in this tutorial because of didactic reasons. :-)
Make sure the file has execution permission (chmod +x /home/hduser/mapper.py
should do the trick) or you will runinto problems.
1 |
|
Reduce step: reducer.py
Save the following code in the file /home/hduser/reducer.py
. It will read the results of mapper.py
fromSTDIN
(so the output format ofmapper.py
and the expected input format of reducer.py
must match) and sum theoccurrences of each word to a final count, and then output its results toSTDOUT
.
Make sure the file has execution permission (chmod +x /home/hduser/reducer.py
should do the trick) or you will runinto problems.
1 |
|
Test your code (cat data | map | sort | reduce)
I recommend to test your mapper.py
and reducer.py
scripts locally before using them in a MapReduce job.Otherwise your jobs might successfully complete but there will be no job result data at all or not the resultsyou would have
expected. If that happens, most likely it was you (or me) who screwed up.
Here are some ideas on how to test the functionality of the Map and Reduce scripts.
1 |
|
Running the Python Code on Hadoop
Download example input data
We will use three ebooks from Project Gutenberg for this example:
- The Outline of Science, Vol. 1 (of 4) by J. Arthur Thomson
- The Notebooks of Leonardo Da Vinci
- Ulysses by James Joyce
Download each ebook as text files in Plain Text UTF-8
encoding and store the files in a local temporary directory ofchoice, for example/tmp/gutenberg
.
1 |
|
Copy local example data to HDFS
Before we run the actual MapReduce job, we must first copy the filesfrom our local file system to Hadoop’s HDFS.
1 |
|
Run the MapReduce job
Now that everything is prepared, we can finally run our Python MapReduce job on the Hadoop cluster. As I said above,we leverage the Hadoop Streaming API for helping us passing data between our Map and Reduce code viaSTDIN
andSTDOUT
.
1 |
|
If you want to modify some Hadoop settings on the fly like increasing the number of Reduce tasks, you can use the-D
option:
1 |
|
and doesn’t manipulate that. You cannot force mapred.map.tasks but can specify mapred.reduce.tasks.
The job will read all the files in the HDFS directory /user/hduser/gutenberg
, process it, and store the results inthe HDFS directory /user/hduser/gutenberg-output
. In general Hadoop will create one output file per reducer; inour
case however it will only create a single file because the input files are very small.
Example output of the previous command in the console:
1 |
|
As you can see in the output above, Hadoop also provides a basic web interface for statistics and information. Whenthe Hadoop cluster is running, open
http://localhost:50030/ in a browser and have a lookaround. Here’s a screenshot of the Hadoop web interface for the job we just ran.
Check if the result is successfully stored in HDFS directory /user/hduser/gutenberg-output
:
1 |
|
You can then inspect the contents of the file with the dfs -cat
command:
1 |
|
Note that in this specific output above the quote signs ("
) enclosing the words have not been inserted by Hadoop.They are the result of how our Python code splits words, and in this case it matched the beginning of a quote in theebook texts.
Just inspect the part-00000
file further to see it for yourself.
Improved Mapper and Reducer code: using Python iterators and generators
The Mapper and Reducer examples above should have given you an idea of how to create your first MapReduce application.The focus was code simplicity and ease of understanding, particularly for beginners of the Python programming language.In a real-world application
however, you might want to optimize your code by usingPython iterators and generators (an evenbetter
introduction in PDF).
Generally speaking, iterators and generators (functions that create iterators, for example with Python’s yield
statement) have the advantage that an element of a sequence is not produced until you actually need it. This can helpa lot in terms
of computational expensiveness or memory consumption depending on the task at hand.
| ./reducer.py” will not work correctly anymore because some functionality is intentionally outsourced to Hadoop.
Precisely, we compute the sum of a word’s occurrences, e.g. ("foo", 4)
, only if by chance the same word (foo
)appears multiple times in succession. In the majority of cases, however, we let the Hadoop group the (key, value) pairsbetween
the Map and the Reduce step because Hadoop is more efficient in this regard than our simple Python scripts.
mapper.py
1 |
|
reducer.py
1 |
|
Related Links
From yours truly:
- Running Hadoop On Ubuntu Linux (Single-Node Cluster)
- Running Hadoop On Ubuntu Linux (Multi-Node Cluster)
From others:
原文链接:http://www.michael-noll.com/tutorials/writing-an-hadoop-mapreduce-program-in-python/