python 实现hadoop的mapreduce

为了用python实现mapreduce,我们先引入下面两个个知识

  • sys.stdin()
  • itertools之groupby

sys模块的简单学习

sys.stdin 是一个文件描述符,代表标准输入,不需使用open函数打开,就可以使用
例如下面的简单程序

  # coding=utf-8
  import sys
 
  for line in sys.stdin:
      print line

执行命令

cat /etc/passwd | python test_stdin.py

cat 是查看 /etc/passwd 文件内容,然后通过管道符 | 传给python程序,这样就可以一行一行的输出内容了(这里passwd是以一个列表的形式传到了test_stidin.py中了)

延伸学习

>>>sys.stdout.write('hello'+'\n') 
hello

#这时屏幕会打印出"hello"字符串(记得还有换行符啊)

那这与Python语言中打印对象调用print obj有什么区别呢,其是事实上就调用了下面的函数sys.stdout.write(obj+"\n")

下面是等价的

1 sys.stdout.write('hello'+'\n') 
2 
3 print 'hello'

下面我们再来看sys.stdin与raw_input这两个标准输入的区别

当我们使用raw_input("Input promption:")时,事实上是先把提示信息输出,然后捕获输入
以下两组在事实上等价:

>>>hi=raw_input('hello? ')
 hello?kaixuan  #这里是需要从键盘上输入
>>>hi
kaixuan

>>print 'hello? '
hello?
>>>hi=sys.stdin.readline()[:-1] # -1 to discard the '\n' in input stream
kaixuan   #键盘上输入
>>>hi
kaixuan

itertools之groupby

groupby()把迭代器中相邻的重复元素挑出来放在一起,实际上挑选规则是通过函数完成的,只要作用于函数的元素返回的值相等,这元素就被认为是在一组的,而函数返回值作为组的key。

from itertools import groupby
from operator import itemgetter
from collections import Iterator
d1 = ['python', 100]
d2 = ['python', 99]
d3 = ['c++', 99]
d4 = ['c++',99]
d5 = ['python', 100]
d = [d1, d2, d3, d4, d5]
d.sort(key=lambda x:x[0], reverse = False )#分组之前先进行排序,改变了已经存在的列表,注意与sorted函数的区别
#排序后[['c++', 99], ['c++', 99], ['python', 100], ['python', 99], ['python', 100]]
lstg = groupby(d,lambda x:x[0])
for key, group in lstg:
    print (key,(isinstance(group,Iterator)))
    for g in group:         #group是一个迭代器
        print (g)

#输出
c++ True
['c++', 99]
['c++', 99]
python True
['python', 100]
['python', 99]
['python', 100]

延伸itemgetter
operator模块提供的itemgetter函数用于获取对象的哪些维的数据,参数为一些序号(对于列表):

a = [1,2,3] 
>>> b=operator.itemgetter(1)      //定义函数b,获取对象的第1个域的值,
>>> b(a) 
2
>>> b=operator.itemgetter(1,0)  //定义函数b,获取对象的第1个域和第0个的值
>>> b(a) 
(2, 1)

思考题:对列表是这样的操作,那么对于dict呢?
上面的sort排序中,我们使用的是lambda函数,如果换成itemgetter又是怎么样呢?(下面的连接中会有相应的答案)

下面是正式开始用Python写mapreduce

创建文件words

python|thread|process
python|xlrd|pyinotiy
python|print|c++
c++|java|php
node.js|javascript|go

上传到hdfs上

hadoop fs -put ./words.txt /storage/kaixuan/data/

编写mapper文件
mapper.py内容如下

# coding=utf-8
import sys
 
for line in sys.stdin:
words = line.strip().split('|')
for word in words:
    print word

Hadoop上面运行,就是使用 HadoopStreaming 来让数据在map 和 reduce之间传递数据,使用sys.stdin获得输入数据,而print 等同于 sys.stdout ,作为标准输出

编写reducer文件

reducer.py内容如下

# coding=utf-8
import sys
from operator import itemgetter
from itertools import groupby

def read_mapper_output(files, separator='\t'):
    for line in files:
        yield line.strip().split(separator, 1)

def main():
    data = read_mapper_output(sys.stdin)
    for key, data in groupby(data, itemgetter(0)):
        count = 0
        for value in data:
            count += 1
        print "{word}\t{count}".format(word=key, count=count)

if __name__ == '__main__':
    main()

在hadoop集群上运行代码

编写run.sh

#!/bin/bash
hadoop fs -rm -r -f /storage/kaixuan/data/wordcount
hadoop jar /usr/hdp/2.6.1.0-129/hadoop-mapreduce/hadoop-streaming.jar \
-jobconf mapreduce.reduce.shuffle.memory.limit.percent=0.1 \
-jobconf mapreduce.reduce.shuffle.input.buffer.percent=0.3 \
-jobconf mapreduce.map.memory.mb=512 \
-jobconf mapreduce.reduce.memory.mb=512 \
-jobconf mapred.map.capacity=100 \
-jobconf mapred.reduce.capacity=100 \
-jobconf mapred.job.name=test_word_count \
-file ./mapper.py     -mapper  "python mapper.py"  \
-file ./reducer.py    -reducer "python reducer.py"  \
-input /storage/kaixuan/data/words.txt -output /storage/zhaoning/data/wordcount

执行结束后,将文件从hadoop上下载下来

hadoop fs -getmerge /storage/kaixuan/data/wordcount wordcount

cat ./wordcount 内容为

xlrd 1
print 1
python 3
javascript 1
process 1
c++ 2
pyinotiy 1
java 1
php 1
go 1
thread 1
node.js 1

延伸:Hadoop Streaming的作用
Hadoop Streaming框架,让任何语言编写的map, reduce程序能够在hadoop集群上运行;map/reduce程序只要遵循从标准输入stdin读,写出到标准输出stdout即可

其次,容易进行单机调试,通过管道前后相接的方式就可以模拟streaming, 在本地完成map/reduce程序的调试

# cat inputfile | mapper | sort | reducer > output

最后,streaming框架还提供了作业提交时的丰富参数控制,直接通过streaming参数,而不需要使用java语言修改;很多mapreduce的高阶功能,都可以通过steaming参数的调整来完成

参考:
标准输入stdin
python重定向sys.stdin、sys.stdout
python中sort和sorted的区别
Python中的分组函数(groupby、itertools)
itertools 模块学习(一)
Python教程:itemgetter对列表排序
用python 写mapreduce程序
Hadoop Streaming详解

你可能感兴趣的:(python 实现hadoop的mapreduce)