Python+Hadoop Streaming实现MapReduce(word count)

来源:互联网 发布:mysql my.ini 编码 编辑:程序博客网 时间:2024/06/16 01:28

1. hadoop本身是用java写的,所以用java写mapreduce是比较合适的,然而hadoop提供了Streaming的方式,让很多语言可以来写mapreduce,下面就介绍如何用python写一个mapreduce程序,我们就从最简单的word count写起吧

2. word count是比较简单的,所以我们直接上代码,

3. map.py

[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #!/usr/bin/env python  
  2. # vim: set fileencoding=utf-8  
  3. import sys  
  4.   
  5. def read_from_input(file):  
  6.     for line in file:  
  7.         yield line.split(' ')  
  8.   
  9.   
  10. def main(separator = ' '):  
  11.     data = read_from_input(sys.stdin)  
  12.     for words in data:  
  13.         for word in words:  
  14.             # write to the reduce  
  15.             print '%s%s%d' % (word, '\t'1)  
  16. if __name__ == '__main__':  
  17.     main()  

这个还是比较简单的,输入是从标准输入得到的,最后输出到reduce端是<word, 1>的形式,相当于用java写的那个context.write(key, value)

4. red.py

[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #!/usr/bin/env python  
  2. # vim: set fileencoding=utf-8  
  3. import sys  
  4. from itertools import groupby  
  5. from operator import itemgetter  
  6.   
  7.   
  8. def read_from_mapper(file, separator):  
  9.     for line in file:  
  10.         yield line.strip().split(separator, 2)  
  11.   
  12. def main(separator = '\t'):  
  13.     data = read_from_mapper(sys.stdin, separator)  
  14.     for current_word, group in groupby(data, itemgetter(0)):  
  15.         try:  
  16.             total_count = sum(int(count) for current_word, count in group)  
  17.             print "%s%s%d" % (current_word, separator, total_count)  
  18.         except ValueError:  
  19.             pass  
  20.   
  21. if __name__ == '__main__':  
  22.     main()  

reduce的代码还是稍微有点复杂的,主要他不像用java写那么简便,会直接给你生成<word, list>这样的形式,所以我们就必须自己进行group,这里就用到了python的几个module:itertools和operator,既然他不给我们<word, list>的形式,那么我们就取构造这样的形式,首先输入是从map端过来的,是<word'\t'1>这样的形式,我们用yield将他们组装成generator, 然后 for current_word, group in groupby(data, itemgetter(0))是在data中进行group。key呢就是data里面项的第一个item,其实就是我们的word,最后用了一个简单的列表推导式进行统计每个word的个数,最后输出。

5. 我们需要用shell来运行他

[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #!/bin/bash  
  2.   
  3.   
  4. hadoop jar ../hadoop-streaming-2.0.0-mr1-cdh4.7.0.jar \  
  5.         -input /user/upsmart/output/qianjc/python/input \  
  6.         -output /user/upsmart/output/qianjc/python/output \  
  7.         -file map.py \  
  8.         -file red.py \  
  9.         -mapper "python map.py" \  
  10.         -reducer "python red.py" \  
  11.         -jobconf mapred.reduce.tasks=1 \  
  12.         -jobconf mapred.job.name="qianjc_test"  

指定hadoop-streaming的jar包位置,几个参数的解释如下:

-input hdfs的输入位置

-output 结果写入hdfs的位置

-file 加载辞典,其实就是在运行的时候会将这些file拷贝到每个tasktracker的机器上

-mapper map的代码

-reducer reduce的代码

-jobconf mapred.reduce.tasks 设置reduce的个数

-jobconf mapred.job.name 设置job的名字

6. 本文主要讲了如何用python写简单mapreduce, 学会了这个处理一些简单的问题就比较迅速了,毕竟写脚本是比较快的

    其实我们可以不直接在集群中运行,我们可以先看看这2个python写得对不对,我们可以这么测试:

    cat xxxx.txt | ./map.py | sort | ./reduce.py,然后看输出对不对

7. 如果想了解更多hadoop streaming编程可以访问如下链接:

http://dongxicheng.org/mapreduce/hadoop-streaming-programming/

http://dongxicheng.org/mapreduce/hadoop-streaming-advanced-programming/

http://www.michael-noll.com/tutorials/writing-an-hadoop-mapreduce-program-in-python/

http://cs.smith.edu/dftwiki/index.php/Hadoop_Tutorial_2_--_Running_WordCount_in_Python



1. 输入文件: 
姓名 年龄(以'/t’分割) 
eg: 
张三  15 
李四  15 
张三  16 
张三 15 

输出:将姓名和年龄相同的归一,并输出其人数 
eg:上述输入,输出为:

姓名  年龄 人数(以'/t’分割) 
张三 15   2 
李四 15   1 
张三 16   1 

2.  map程序:

 

#include 
#include 
 
using namespace std;
 
int main(int argc, char** argv)
{
    string name,age;
 
    //读入姓名、年龄
    while(cin >> name >> age)
    {
        //输出姓名、年龄、人数
        cout << name << "/t" << age  << "/t" << "1" << endl;
    }
    return 0;
}

 

编译生成可执行程序: 
g++ -o mapper mapper.cpp

3. reducer程序:

#include 
#include 
#include 
 
using namespace std;
 
int main(int argc, char** argv)
{
    string key, value;
    int num;
    
    //个数统计
    mapint> count_stat;
    mapint>::iterator it_count_stat;
    
    //读入数据并插入map
    while(cin >> key >> value >> num)
    {
        string tmp_key = key + "/t" + value;
    
        //插入数据
        it_count_stat = count_stat.find(tmp_key);
        if(it_count_stat != count_stat.end())
        {
            (it_count_stat->second)++;
        }
        else
        {
            count_stat.insert(make_pair(tmp_key, 1));
        }
    }
 
    //输出统计结果
    for(it_count_stat = count_stat.begin(); it_count_stat != count_stat.end(); it_count_stat++)
    {
        cout<first<<"/t"<second<      
    }
 
    return 0;
}


编译生成可执行程序: 
g++ -o reducer reducer.cpp

 

4. 测试数据:

张三    15
李四    20
张三    15
张三    16

 

5. 单机测试运行:

$ cat test.txt | ./mapper  | ./reducer 
    李四    20    1
    张三    15    2
    张三    16    1

 

6. Hadoop集群运行: 
   以'/t’作为分隔符,并以前两个字段作为key,reduce任务3个,输入命令:

$ hadoop fs -put test.txt /user/test.txt
$ hadoop streaming -D stream.map.output.field.separator='/t' /
    -D stream.num.map.output.key.fields=2 /
    -input /user/test.txt /
    -output /user/tmp_1324 /
    -mapper ./mapper -reducer ./reducer /
    -file mapper -file reducer /
    -jobconf mapred.reduce.tasks=3 /
    -jobconf mapre.job.name="c++_test" 

 

7.查看输出:

$ hadoop fs -cat /user/tmp_1324/part-00000
李四    20      1
张三    16      1
$ hadoop fs -cat /user/part-00001
$ hadoop fs -cat /user/part-00002
张三    15      2

 


0 0
原创粉丝点击