Python Hadoop Mapreduce 实现Hadoop Streaming分组和二次排序

如果对各个定义参数,看后还是不理解,可以先看下面三个参考了。
参考一
参考二
参考三

需求:公司给到一份全国各门店销售数据,要求:1.按门店市场分类,将同一市场的门店放到一起;2.将各家门店按销售额从大到小,再按利润从大到小排列

一 需求一:按市场对门店进行分组

分组(partition)

Hadoop streaming框架默认情况下会以’/t’作为分隔符,将每行第一个’/t’之前的部分作为key,其余内容作为value,
如果没有’/t’分隔符,则整行作为key;这个key/value对又作为该map对应的reduce的输入。

-D stream.map.output.field.separator 指定key,value分隔符,默认是/t ,实例如下:
-D stream.map.output.field.separator=,
将key,value以,作为分隔符

-D stream.num.map.output.key.fields 选择key的范围 
-D stream.num.map.output.key.fields=3
选择前三个字段作为key,即数据shuffle时候的key,由三个字段组成

-D map.output.key.field.separator 指定key内部的分隔符 
-D map.output.key.field.separator=,
key直接是以,分割的

-D num.key.fields.for.partition 指定对key分出来的前几部分做partition而不是整个key 
-D num.key.fields.for.partition=1 
选择第一个key来进行分桶,如果想选择任意key作为分桶,则如下
-D mapred.text.key.partitioner.options=-k1,2 
附注:-k1,2 指定对key进行划分后第1 2个域进行划分(没有试过,可以尝试一下)

1.2.数据

数据字典
store_code(店id),market_code(市场id),income(收入),pay(支出)

mcd_sale.csv
ch_sh_0003,ch_sh,500,200
ch_bj_0001,ch_bj,600,300
ch_bj_0002,ch_bj,1500,700
ch_wh_0001,ch_wh,500,200
ch_wh_0002,ch_wh,800,500
ch_sh_0001,ch_sh,1000,600
ch_sh_0002,ch_sh,800,600
ch_sh_0004,ch_sh,500,200
ch_bj_0003,ch_bj,500,200

mapreduce_partition.sh

-D map.output.key.field.separator=, \ # key内部分隔符
-D num.key.fields.for.partition=1 \ # 用第一个key分桶
完整脚本如下(亲测可以运行)
HADOOP_CMD="/root/apps/hadoop-2.6.4/bin/hadoop"
STREAM_JAR_PATH="/root/apps/hadoop-2.6.4/share/hadoop/tools/lib/hadoop-streaming-2.6.4.jar"
INPUT_FILE_PATH="/data/data_coe/data_asset/bigdata/mapreduce/*.csv"
OUTPUT_PATH="/data/data_coe/data_asset/bigdata/output2"
hdfs dfs -rmr  $OUTPUT_PATH 
$HADOOP_CMD jar $STREAM_JAR_PATH \
-D stream.map.input.ignoreKey=true \
-D map.output.key.field.separator=, \
-D num.key.fields.for.partition=1 \
-numReduceTasks 3 \
-input $INPUT_FILE_PATH \
-output $OUTPUT_PATH \
-mapper "python map.py" \
-reducer "python reduce.py" \
-file ./map.py \
-file ./reduce.py \
-partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner

map.py

# !/usr/bin/python
# -*- coding: utf-8 -*-
# @Time    : 2018/10/27 下午12:36
# @Author  : Einstein Yang!!
# @Nickname : 穿着开裆裤上大学
# @FileName: map_separator.py
# @Software: PyCharm
# @PythonVersion: python3.5
# @Blog    :https://blog.csdn.net/weixin_41734687

import sys
for line in sys.stdin:
    line = line.strip()
    seq = line.split(",")
    if len(seq) >=4:
        store_code = seq[0]
        market_code = seq[1]
        income = seq[2]
        pay = seq[3]
        try:
            netincome = int(income) - int(pay)
        except:
            netincome = 0
        print(market_code+ "," + store_code + "\t" + income + "," + pay + "," + str(netincome))

reduce.py

# coding=utf-8

import sys
for line in sys.stdin:
    line = line.strip()
    print line

查看结果

hdfs dfs -ls /data/data_coe/data_asset/bigdata/output2/

-rw-r--r--   2 root supergroup          0 2018-10-28 05:30 /data/data_coe/data_asset/bigdata/output2/_SUCCESS
-rw-r--r--   2 root supergroup          0 2018-10-28 05:30 /data/data_coe/data_asset/bigdata/output2/part-00000
-rw-r--r--   2 root supergroup        205 2018-10-28 05:30 /data/data_coe/data_asset/bigdata/output2/part-00001
-rw-r--r--   2 root supergroup         58 2018-10-28 05:30 /data/data_coe/data_asset/bigdata/output2/part-00002


part-00000(无内容)

part-00001
ch_bj,ch_bj_0001	600,300,300
ch_bj,ch_bj_0002	1500,700,800
ch_bj,ch_bj_0003	500,200,300
ch_sh,ch_sh_0001	1000,600,400
ch_sh,ch_sh_0002	800,600,200
ch_sh,ch_sh_0003	500,200,300
ch_sh,ch_sh_0004	500,200,300

part-00002
ch_wh,ch_wh_0001	500,200,300
ch_wh,ch_wh_0002	800,500,300

二 需求二 按销售额从大到小,在按利润大到小

map.output.key.field.separator 设置key内的字段分隔符
num.key.fields.for.partition 设置key内前几个字段用来做partition

事实上KeyFieldBasePartitioner还有一个高级参数 mapred.text.key.partitioner.options,这个参数可以认为是 num.key.fields.for.partition的升级版,它可以指定不仅限于key中的前几个字段用做partition,而是可以单独指定 key中某个字段或者某几个字段一起做partition。
比如上面的需求用mapred.text.key.partitioner.options表示为
mapred.text.key.partitioner.options=-k1,1
注意mapred.text.key.partitioner.options和num.key.fields.for.partition不需要一起使用,一起使用则以num.key.fields.for.partition为准。

二次排序(Secondary Sort)

mapper的输出被partition到各个reducer之后,会有一步排序。默认是按照key做二次排序,如果key是多列组成,先按照第一列排序,第一列相同的,按照第二列排序
如果需要自定义排序。这里要控制的就是key内部的哪些元素用来做排序依据,是排字典序还是数字序,倒序还是正序。用来控制的参数是mapred.text.key.comparator.options。

mapredue_partitionsort.sh

HADOOP_CMD="/root/apps/hadoop-2.6.4/bin/hadoop"
STREAM_JAR_PATH="/root/apps/hadoop-2.6.4/share/hadoop/tools/lib/hadoop-streaming-2.6.4.jar"
INPUT_FILE_PATH="/data/data_coe/data_asset/bigdata/mapreduce/*.csv"
OUTPUT_PATH="/data/data_coe/data_asset/bigdata/output2"
hdfs dfs -rmr  $OUTPUT_PATH 
$HADOOP_CMD jar $STREAM_JAR_PATH \
-D stream.map.input.ignoreKey=true \
-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,1 \
-D mapred.output.key.comparator.class=org.apache.hadoop.mapred.lib.KeyFieldBasedComparator \
-D mapred.text.key.comparator.options="-k3,3nr -k4nr" \
-numReduceTasks 1 \
-input $INPUT_FILE_PATH \
-output $OUTPUT_PATH \
-mapper "python map_sort.py" \
-reducer "python reduce_sort.py" \
-file ./map_sort.py \
-file ./reduce_sort.py \
-partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner 

map_sort.py

# !/usr/bin/python
# -*- coding: utf-8 -*-
# @Time    : 2018/10/27 下午12:36
# @Author  : Einstein Yang!!
# @Nickname : 穿着开裆裤上大学
# @FileName: map_separator.py
# @Software: PyCharm
# @PythonVersion: python3.5
# @Blog    :https://blog.csdn.net/weixin_41734687

import sys
for line in sys.stdin:
    line = line.strip()
    seq = line.split(",")
    if len(seq) >=4:
        store_code = seq[0]
        market_code = seq[1]
        income = seq[2]
        pay = seq[3]
        try:
            netincome = int(income) - int(pay)
        except:
            netincome = 0
        print(market_code+ "," + store_code + "," + income + "," + str(netincome) + "," + pay )

reduce_sort.py

# coding=utf-8


import sys
for line in sys.stdin:
    line = line.strip()
    print line

结果查看

ch_bj,ch_bj_0002,1500,800	700
ch_sh,ch_sh_0001,1000,400	600
ch_wh,ch_wh_0002,800,300	500
ch_sh,ch_sh_0002,800,200	600
ch_bj,ch_bj_0001,600,300	300
ch_wh,ch_wh_0001,500,300	200
ch_sh,ch_sh_0003,500,300	200
ch_bj,ch_bj_0003,500,300	200
ch_sh,ch_sh_0004,500,300	200

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_41734687/article/details/83478497