• Python开发MapReduce系列(二)Python实现MapReduce分桶


    版权声明:本文为博主原创文章,未经博主允许不得转载
     
    首先,先引出两点来展开下面的话题。
    (1)map阶段的排序是在hash之后,写入磁盘之前进行。排序的两个关键字是partition(分区编号)和key。
    (2)map结束后,并不是马上写到磁盘的,而是有个环形缓冲区,数据写到缓冲区中,默认溢出率是80%(这个值可以通过属性设置 io.sort.mb),每达到溢出条件就溢出生成一个小文件,直到全部数据写完,最后把所有的小文件合并成一个大文件,并写到磁盘中。这样做的目的是减少磁盘寻道时间,让每个map只输出一个文件,并为这个文件提供索引文件,记录下每个reduce对应数据的偏移量.(其实就是为map与reduce之间的分发建立映射关系)
     
    1、默认情况介绍
        在hadoop streaming的默认情况下,是以” ”作为分隔符的。对于标准输入来说,以每行读取到的数据的第一个” ”为分界线, 在其之前的部分为key,在其之后的为value。如果一个 " " 字符没有,则整行都被当做是key处理。
     
    2、MapReduce shuffler过程中的sort和partition阶段
        mapper阶段除了用户代码,最重要的是shuffle 过程,这个过程是MapReduce耗时和消耗资源的主要地方,因为其涉及到磁盘的写入等操作。这里先不谈优化方面的处理,只研究shuffle 过程中的sort和partition两个过程。为什么只研究这两个过程,因为,sort和partition是MapReduce的核心思想,整个过程就是在不断的重复 排列和分割 的操作。
        从第1点可以知道,MapReduce的key默认是以 分割得到的,我们能不能根据自己的需要来获取到特定形式的key?实现类似分桶、根据指定列的排序之类的自由排序呢?答案是可以的。我们可以通过以下的参数来实现:
     
    3、相关的参数介绍
    3.1map阶段
    -jobconf mapred.reduce.tasks=2【此属性针对下面的例子都有效】
     
         map.output.key.field.separator:指定map输出<key,value>对之后,其中key内部的分割符。
         num.key.fields.for.partition:指定分桶时,按照分隔符切割后,用于分桶key所占的列数。
         -partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner:前两个参数,要配合这个partitioner,没有的话会报错
    例如:map.output.key.field.separator=,      
         num.key.fields.for.partition=2      
         -partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner                   
    一行数据:1 , 2 , 3 , 4 , 5(在这里1 2 之间的逗号是key内部的分隔符,并且1,2格式key的数据分为到同一桶)
     
         stream.map.output.field.separator: map中的key与value的分隔符
         stream.num.map.output.key.fields:指定map输出按照分隔符切割后,key所占有的列数,之前的是key,之后的是value 
    例如:map.output.key.field.separator=,      
         num.key.fields.for.partition=2      
         -partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner      
         stream.map.output.field.separator=:             
         stream.num.map.output.key.fields=3
         输入:1 , 2 , 3 , 4 , 5  
              1 , 2 , 2 , 4 , 5
              1 , 3 , 4 , 4 , 5
              1 , 3 , 3 , 4 , 5
     
        输出part-00000:1 , 2 , 2 : 4 , 5  
                       1 , 2 , 3 : 4 , 5
     
        输出part-00000:1 , 3 , 3 : 4 , 5
                       1 , 3 , 4 : 4 , 5
        1 , 2 是分桶值,1 , 2 , 3是key, 4 , 5是value。在这里1 2 之间的逗号是key内部的分隔符,1 , 2格式key的数据分为到同一桶

    3.2 reduce阶段

    stream.reduce.output.field.separator:reduce中key与value的分隔符 
    stream.num.reduce.output.key.fields:reduce中分隔符的位置
    3、分桶测试
    run.sh脚本(作为一个会偷懒的程序猿,能偷懒就偷懒,写个脚本省掉每次写入一大串指令的烦恼)
     
    HADOOP_CMD="/home/hadoop/hadoop/bin/hadoop"
    STREAM_JAR_PATH="/home/hadoop/hadoop/contrib/streaming/hadoop-streaming-1.2.1.jar"
    INPUT_PATH_A="/a.txt"
    INPUT_PATH_B="/b.txt"
    OUTPUT_PATH="/output"
    $HADOOP_CMD fs -rmr  $OUTPUT_PATH    #mapreduce在运行时,文件系统不能存在output目录(目录名字随意)
    
    $HADOOP_CMD jar $STREAM_JAR_PATH 
        -input $INPUT_FILE_PATH_A,$INPUT_FILE_PATH_B
        -output $OUTPUT_SORT_PATH 
        -mapper "python map.py" 
        -reducer "python red.py" 
        -file ./map.py 
        -file ./red.py 
        -jobconf mapred.reduce.tasks=2 
        -jobconf map.output.key.field.separator=, 
        -jobconf num.key.fields.for.partition=2     
        -partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner 
        -jobconf stream.map.output.field.separator=: 
        -jobconf stream.num.map.output.key.fields=3

    a.txt内容

    1,2,3:hadoop
    1,2,1:hadoop
    1,2,5:hadoop
    1,3,4:hadoop
    1,2,9:hadoop
    1,2,11:hadoop
    1,2,7:hadoop
    1,3,15:hadoop
    1,3,14:hadoop
    1,2,19:hadoop
     
    b.txt内容
    1,2,0:java
    1,2,2:java
    1,2,8:java
    1,3,4:java
    1,2,2:java
    1,2,14:java
    1,2,12:java
    1,3,1:java
    1,3,5:java
    1,2,3:java

    4、结果输出

    【part-00000】输出内容如下:
    1,2,0:java
    1,2,1:hadoop
    1,2,2:java
    1,2,2:java
    1,2,3:hadoop
    1,2,3:java
    1,2,5:hadoop
    1,2,7:hadoop
    1,2,8:java
    1,2,9:hadoop
    1,2,11:hadoop
    1,2,14:java
    1,2,19:hadoop
    【part-00001】输出内容如下:
    1,3,1:java
    1,3,4:hadoop
    1,3,4:java
    1,3,5:java
    1,3,14:hadoop
    1,3,15:hadoop

    5、结果分析

    由结果可以看出:
    (1)以前2列为分桶标志,因为part-00000,part-00001分别以1,2和1,3开头。
    (2)以前3列为key,并且第3列为分桶之后排序的key。
    (3)key内部之间是以 , 分隔。
    (4)key与value之间是以 : 分隔。
     
    参考:
    (1)《Hadoop技术内幕:深入解析MapReduce架构设计与实现原理》
  • 相关阅读:
    关于android sdk 与 Eclipse 的一些错误的解决注意事项
    Java2D范例 ——创建一副地图
    大河奔流的精神 ——俞敏洪
    利用异或进行两个数的交换
    Android中怎么使图片显示
    JDK源码学习笔记——HashSet LinkedHashSet TreeSet
    JDK源码学习笔记——TreeMap及红黑树
    HashMap与Hashtable
    JDK源码学习笔记——LinkedHashMap
    JDK源码学习笔记——HashMap
  • 原文地址:https://www.cnblogs.com/liangjf/p/7586457.html
Copyright © 2020-2023  润新知