streaming 使用

轉自:http://www.cnblogs.com/joyeecheung/p/3841952.html


相關隨筆:


指定partition的時候不能用 “\t” 作分割符,不識別

使用額外的文件

假如你跑的job除了輸入以外還需要一些額外的文件(side data),有兩種選擇:

  1. 大文件

    所謂的大文件就是大小大於設置的local.cache.size的文件,默認是10GB。這個時候可以用-file來分發。除此之外代碼本身也可以用file來分發。

    格式:假如我要加多一個sideData.txt給python腳本用:

    複製代碼
    $HADOOP_HOME/bin/hadoop  jar $HADOOP_HOME/hadoop-streaming.jar \
        -input iputDir \
        -output outputDir \
        -mapper mapper.py \
        -file mapper.py \
        -reducer reduer.py \
        -file reducer.py \
        -file sideDate.txt
    
    複製代碼

    在python腳本里,只要把這個文件當成自己同一目錄下的本地文件來打開就可以了。比如:

    f = open("sideData.txt")
    

    注意這個file是隻讀的,不可以寫。

  2. 小文件

    如果是比較小的文件,想要提高讀寫速度可以將它放在distributed cache裏(也就是每臺機器都有自己的一份copy,不需要網絡IO就可以拿到數據)。這裏要用到的參數是-cachefile,寫法和用法上一個一樣,就是-file改成-cachefile而已。

控制partitioner

partitioning指的是數據經過mapper處理後,被分發到reducer上的過程。partitioner控制的,就是“怎樣的mapper輸出會被分發到哪一個reducer上”。

Hadoop有幾個自帶的partitioner,解釋可以看這裏。默認的是HashPartitioner,也就是把第一個tab前的key做hash之後用於分配partition。寫Hadoop Streaming程序是可以選擇其他partitioner的,你可以選擇自帶的其他幾種裏的一種,也可以自己寫一個繼承Partitioner的java類然後編譯成jar,在運行參數裏指定爲你用的partitioner。

官方自帶的partitioner裏最常用的是KeyFieldBasedPartitioner(源代碼可以看這裏)。它會按照key的一部分來做partition,而不是用整個key來做partition。

在學會用KeyFieldBasedPartitioner之前,必然要先學怎麼控制key-value的分割。分割key的步驟可以分爲兩步,用python來描述一下大約是

fields = output.split(seperator)
key = fields[:numKeyfields]
  1. 選擇用什麼符號來分割key,也就是選擇seperator

    map.output.key.field.separator可以指定用於分隔key的符號。比如指定爲一點的話,就要加上參數

    -D stream.map.output.field.separator=.
    

    假設你的mapper輸出是

    11.22.33.44
    

    這時會先看準[11, 22, 33, 44]這裏的其中一個或幾個作爲key

  2. 選擇key的範圍,也就是選擇numKeyfields

    控制key的範圍的參數是這個,假設我要設置被分割出的前2個元素爲key:

    -D stream.num.map.output.key.fields=2
        

    那麼key就是上面的 1122。值得注意的是假如這個數字設置到覆蓋整個輸出,在這個例子裏是4的話,那麼整一行都會變成key。

上面分割出key之後, KeyFieldBasedPartitioner還需要知道你想要用key裏的哪部分作爲partition的依據。它進行配置的過程可以看源代碼來理解。

假設在上一步我們通過使用

-D stream.map.output.field.separator=. \
-D stream.num.map.output.key.fields=4 \
    

將11.22.33.44的整個字符串都設置成了key,下一步就是在這個key的內部再進行一次分割。map.output.key.field.separator可以用來設置第二次分割用的分割符,mapred.text.key.partitioner.options可以接受參數來劃分被分割出來的partition key,比如:

-D map.output.key.field.separator=. \
-D mapred.text.key.partitioner.options=-k1,2 \
    

指的就是在key的內部裏,將第1到第2個被點分割的元素作爲partition key,這個例子裏也就是1122。這裏的值-ki,j表示從i到j個元素(inclusive)會作爲partition key。如果終點省略不寫,像-ki的話,那麼i和i之後的元素都會作爲partition key。

partition key相同的輸出會保證分到同一個reducer上,也就是所有11.22.xx.xx的輸出都會到同一個partitioner,11.22換成其他各種組合也是一樣。

實例說明一下,就是這樣的:

  1. mapper的輸出是

    11.12.1.2
    11.14.2.3
    11.11.4.1
    11.12.1.1
    11.14.2.2
    
  2. 指定前4個元素做key,key裏的前兩個元素做partition key,分成3個partition的話,就會被分成

    複製代碼
    11.11.4.1
    -----------
    11.12.1.2
    11.12.1.1
    -----------
    11.14.2.3 
    11.14.2.2
    複製代碼
  3. 下一步reducer會對自己得到的每個partition內進行排序,結果就是

    複製代碼
    11.11.4.1
    -----------
    11.12.1.1
    11.12.1.2
    -----------
    11.14.2.2
    11.14.2.3 
    複製代碼

命令格式大約就是長這樣

複製代碼
$HADOOP_HOME/bin/hadoop  jar $HADOOP_HOME/hadoop-streaming.jar \
        -D stream.map.output.field.separator=. \
        -D stream.num.map.output.key.fields=4 \
        -D map.output.key.field.separator=. \
        -D mapred.text.key.partitioner.options=-k1,2 \
        -input inputDir \
        -output outputDir \
        -mapper mapper.py -file mapper.py \
        -reducer reducer.py -file reducer.py \
        -partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner 
    
複製代碼

注意-D參數放在前面,指定用KeyFieldBasedPartitioner的-partitioner要放在下面。

控制comparator與自定義排序

上面說到mapper的輸出被partition到各個reducer之後,會有一步排序。這個排序的標準也是可以通過設置comparator控制的。和上面一樣,要先設置分割出key用的分隔符、key的範圍,key內部分割用的分隔符

-D stream.map.output.field.separator=. \
-D stream.num.map.output.key.fields=4 \
-D map.output.key.field.separator=. \

這裏要控制的就是key內部的哪些元素用來做排序依據,是排字典序還是數字序,倒序還是正序。用來控制的參數是mapred.text.key.comparator.options,接受的值格式類似於unix sort。比如我要按第二個元素的數字序(默認字典序)+倒序來排元素的話,就用

-D mapred.text.key.comparator.options=-k2,2nr

n表示數字序,r表示倒序。這樣一來

11.12.1.2
11.14.2.3
11.11.4.1
11.12.1.1
11.14.2.2

就會被排成

11.14.2.3
11.14.2.2
11.12.1.2
11.12.1.1
11.11.4.1




eg:



hadoop jar /usr/lib/hadoop-0.20-mapreduce/contrib/streaming/hadoop-streaming.jar \
       -input $output \
       -output $output2 \
       -mapper "cat" \
       -reducer "awk 'BEGIN{FS=\"\t\";OFS=\",\";tp=0;tp2=0;n=0}{split(\$1,d,\",\");if(tp==0){tp=d[1];tp2=d[2];n=1}else if(tp!=d[1]){print tp,n;tp=d[1];tp2=d[2];n=1}else if(tp2!=d[2]){n++;tp2=d[2]}}END{print tp,n}'" \
       -jobconf stream.map.output.field.separator="," \
       -jobconf stream.num.map.output.key.fields=2 \
       -jobconf map.output.key.field.separator="," \
       -jobconf num.key.fields.for.partition=1 \
       -partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner \
        -jobconf mapred.reduce.tasks=10 \
       -jobconf mapred.job.name="hh" \ 

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