什麼是Hadoop?
Google為自己的業務需要提出了程式設計模型MapReduce和分散式檔案系統Google File System,併發布了相關論文(可在Google Research的網站上獲得: GFS 、 MapReduce)。 Doug Cutting和Mike Cafarella在開發搜尋引擎Nutch時對這兩篇論文做了自己的實現,即同名的MapReduce和HDFS,合起來就是Hadoop。
MapReduce的Data flow如下圖,原始資料經過mapper處理,再進行partition和sort,到達reducer,輸出最後結果。
圖片來自Hadoop: The Definitive Guide
Hadoop Streaming原理
Hadoop本身是用JAVA開發的,程式也需要用JAVA編寫,但是通過Hadoop Streaming,我們可以使用任意語言來編寫程式,讓Hadoop運行。
Hadoop Streaming的相關原始程式碼可以在Hadoop的Github repo 查看。 簡單來說,就是通過將用其他語言編寫的mapper和reducer通過參數傳給一個事先寫好的JAVA程式(Hadoop自帶的*- streaming.jar),這個JAVA程式會負責創建MR作業, 另開一個進程來運行mapper,將得到的輸入通過stdin傳給它,再將 mapper處理後輸出到stdout的資料交給Hadoop,partition和sort之後,再另開進程運行reducer,同樣地通過 stdin/ stdout得到最終結果。 因此,我們只需要在其他語言編寫的程式裡,通過stdin接收資料,再將處理過的資料輸出到 stdout,Hadoop streaming就能通過這個JAVA的wrapper幫我們解決中間繁瑣的步驟,運行分散式程式。
圖片來自Hadoop: The Definitive Guide
原理上只要是能夠處理stdio的語言都能用來寫mapper和reducer,也可以指定mapper或reducer為Linux下的程式(如 awk、grep、cat)或者按照一定格式寫好的java class。 因此,mapper和reducer也不必是同一類的程式。
Hadoop Streaming的優缺點
優點
可以使用自己喜歡的語言來編寫MapReduce程式(換句話說,不必寫JAVA XD)
不需要像寫JAVA的MR程式那樣import一大堆庫,在代碼裡做一大堆配置,很多東西都抽象到了stdio上,代碼量顯著減少
因為沒有庫的依賴,調試方便,並且可以脫離Hadoop先在本地用管道類比調試
缺點
只能通過命令列參數來控制MapReduce框架,不像JAVA的程式那樣可以在代碼裡使用API,控制力比較弱,有些東西鞭長莫及
因為中間隔著一層處理,效率會比較慢
所以Hadoop Streaming比較適合做一些簡單的任務,比如用python寫只有一兩百行的腳本。 如果專案比較複雜,或者需要進行比較細緻的優化,使用Streaming就容易出現一些束手束腳的地方。
用python編寫簡單的Hadoop Streaming程式
這裡提供兩個例子:
Michael Noll的word count程式
Hadoop: The Definitive Guide裡的常式
使用python編寫Hadoop Streaming程式有幾點需要注意:
在能使用iterator的情況下,儘量使用iterator,避免將stdin的輸入大量儲存在記憶體裡,否則會嚴重降低性能
streaming不會幫你分割key和value傳進來,傳進來的只是一個個字串而已,需要你自己在代碼裡手動調用split()
從stdin得到的每一行資料末尾似乎會有\n,保險起見一般都需要使用rstrip()來去掉
在想獲得K-V list而不是一個個處理key-value pair時,可以使用groupby配合itemgetter將key相同的k-v pair組成一個個group, 得到類似JAVA編寫的reduce可以直接獲取一個Text類型的key和一個iterable作為value的效果。 注意itemgetter的效率比lambda運算式要高,所以如果需求不是很複雜的話,儘量用itemgetter比較好。
我在編寫Hadoop Streaming程式時的基本模版是
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Some description here...
"""
import sys
from operator import itemgetter
from itertools import groupby
def read_input(file):
"""Read input and split."""
for line in file:
yield line.rstrip().split('\t')
def main():
data = read_input(sys.stdin)
for key, kviter in groupby(data, itemgetter(0)):
# some code here..
if __name__ == "__main__":
main()
如果對輸入輸出格式有不同于預設的控制,主要會在read_input()裡調整。
本地調試
本地調試用於Hadoop Streaming的python程式的基本模式是:
$ cat | python | sort -t $'\t' -k1,1 | python >
或者如果不想用多餘的cat,也可以用<定向
$ python < | sort -t $'\t' -k1,1 | python >
這裡有幾點需要注意:
Hadoop預設按照tab來分割key和value,以第一個分割出的部分為key,按key進行排序,因此這裡使用
sort -t $'\t' -k1,1
來類比。 如果你有其他需求,在交給Hadoop Streaming執行時可以通過命令列參數調,本地調試也可以進行相應的調整,主要是調整sort的參數。 因此為了能夠熟練進行本地調試,建議先掌握sort命令的用法。
如果你在python腳本里加上了shebang,並且為它們添加了執行許可權,也可以用類似于
./mapper.py
來代替
python mapper.py
原文連結:HTTP://www.cnblogs.com/joyeecheung/p/3757915.html