【hadoop】Hadoop學習筆記(四):Hadoop中的streaming

Hadoop爲MapReduce提供了一個允許你使用除了java以外的語言編寫map,reduce函數的API:Hadoop Streaming使用標準流(standard streams)作爲Hadoop和應用程序之間傳輸數據的接口。所以你可以使用任何語言編寫map,reduce函數,只要它能夠從標準輸入流(stdin)中讀入數據,以及向標準輸出流(stdout)中寫輸出數據就行

  Streaming本質上就非常適合處理文本數據。Map輸入數據通過stdin傳輸到map函數中,map函數再一行一行的處理這些輸入數據,然後被處理過的以tab分割的鍵值對被寫到stdout中去,reduce函數從stdin中接收到這些map輸出(Hadoop框架保證這些map輸出是經過關鍵字排序的),然後把處理後的reduce輸出寫到stdout中。

 以ruby爲例

  以學習筆記(一)中的計算MaxTemperature的程序爲例,其Map函數的ruby代碼表示如下(即使你像我一樣沒接觸過ruby,你一樣可以讀懂下面這段代碼):

1 #!/usr/bin/env ruby
2 STDIN.each_line do |line|
3   val = line
4   year, temp, q = val[15,4], val[87,5], val[92,1]
5   puts "#{year}\t#{temp}" if (temp != "+9999" && q =~ /[01459]/)
6 end

  這個程序爲從stdin中讀入的每行數據執行此代碼塊。這段代碼塊從每行中抽取出相關的字段(年份,溫度和質量),如果溫度值有效,就把年份和溫度值寫入到stdout中去(以tab鍵分隔開)。

  因爲該腳本只是在標準輸入和輸出上運行,所以最簡單的方式就是在unix pipe上進行測試,而不是使用hadoop:

% cat input/ncdc/sample.txt | ch02/src/main/ruby/max_temperature_map.rb
1950 +0000
1950 +0022
1950 -0011
1949 +0111
1949 +0078

  相應的,ruby形式的reduce函數如下所示:

複製代碼
 1 #!/usr/bin/env ruby
 2 last_key, max_val = nil, -1000000
 3 STDIN.each_line do |line|
 4   key, val = line.split("\t")
 5   if last_key && last_key != key
 6     puts "#{last_key}\t#{max_val}"
 7     last_key, max_val = key, val.to_i
 8   else
 9     last_key, max_val = key, [max_val, val.to_i].max
10   end
11 end
12 puts "#{last_key}\t#{max_val}" if last_key
複製代碼

  同樣的,這段代碼迭代從stdin中讀入的每一行,但是我們必須爲當前正在處理的每一個key group保存一些數據。在這個例子中,key是年份值,我們把上一次處理過的年份值last_key和迄今爲止對應的該key group中最大的溫度值max_val存儲下來。MapReduce框架會確保這些key值是經過排序的,所以當我們遇到一個不同的key值時,說明上一個key group已經處理完了,所保存的最大溫度值max_val就是該key group最大的溫度值。對比一下java實現,我們可以發現,java API會自動的爲你分組,而在ruby中你不得不自己確定key group的界限。

  對於每一行,我們抽取出年份和溫度值,如果我們已經處理完了一組key-value pair(last_key && last_key != key),我們就把last_key和max_value(仍然以tab鍵分開)寫入到stdout中去,然後重新設置last_key,max_value爲對應的新值。如果還沒有處理完某個key group,我們就只是更新下當前last_key所對應的max_value。現在我們仍然用unix pipe來模擬下整個mapreduce過程:

% cat input/ncdc/sample.txt | ch02/src/main/ruby/max_temperature_map.rb | \
sort | ch02/src/main/ruby/max_temperature_reduce.rb
1949 111
1950 22

  可以看到,這次輸出跟java對應的輸出是一樣的,現在我們使用Hadoop來運行一下。由於hadoop命令不支持streaming選項,所以你必須通過jar選項聲明要處理streaming 的streaming jar文件。如下所示:

% hadoop jar $HADOOP_INSTALL/contrib/streaming/hadoop-*-streaming.jar \
-input input/ncdc/sample.txt \
-output output \
-mapper ch02/src/main/ruby/max_temperature_map.rb \
-reducer ch02/src/main/ruby/max_temperature_reduce.rb

  如果是在一個較大的集羣上運行改程序,我們可以使用-combiner選項來聲明一個combiner(關於combiner的內容請參看學習筆記(三))。早前的版本combiner可能限定於java代碼實現,但在1.x以後的版本中,combiner可以是任意的streaming命令。如下所示:

% hadoop jar $HADOOP_INSTALL/contrib/streaming/hadoop-*-streaming.jar \
-input input/ncdc/all \
-output output \
-mapper "ch02/src/main/ruby/max_temperature_map.rb | sort |
ch02/src/main/ruby/max_temperature_reduce.rb" \
-reducer ch02/src/main/ruby/max_temperature_reduce.rb \
-file ch02/src/main/ruby/max_temperature_map.rb \
-file ch02/src/main/ruby/max_temperature_reduce.rb

  在本例中,我們指定輸入文件爲一個目錄(-input input/ncdc/all),這樣就把該目錄下的所有文件讀入mapper中了(在本例中此目錄下是兩個.gz文件,也就是gzip的壓縮文件:1901.gz,1902.gz)。其中-file選項用來說明要拷貝到集羣上的文件(如果是在單例模式下運行就不需要這麼做了)。值得注意的是,此例中的-mapper選項同時指明瞭mapper和combiner(也就是max_temperature_reduce.rb,還記得嗎,在學習筆記(三)中我們知道java代碼的combiner跟reducer是同一實現)

   以Python爲例

  熟悉python的同學可以參考一下python下map和reduce函數的代碼::

複製代碼
1 #!/usr/bin/env python
2 import re
3 import sys
4 for line in sys.stdin:
5   val = line.strip()
6   (year, temp, q) = (val[15:19], val[87:92], val[92:93])
7   if (temp != "+9999" and re.match("[01459]", q)):
8     print "%s\t%s" % (year, temp)
複製代碼
複製代碼
 1 #!/usr/bin/env python
 2 import sys
 3 (last_key, max_val) = (None, -sys.maxint)
 4 for line in sys.stdin:
 5   (key, val) = line.strip().split("\t")
 6   if last_key and last_key != key:
 7     print "%s\t%s" % (last_key, max_val)
 8     (last_key, max_val) = (key, int(val))
 9   else:
10     (last_key, max_val) = (key, max(max_val, int(val)))
11 if last_key:
12   print "%s\t%s" % (last_key, max_val)
複製代碼

  執行測試腳本命令爲:

% cat input/ncdc/sample.txt | ch02/src/main/python/max_temperature_map.py | \
sort | ch02/src/main/python/max_temperature_reduce.py
1949 111
1950 22

轉載請註明出處:http://www.cnblogs.com/beanmoon/archive/2012/12/07/2807759.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章