Hadoop-SecondarySort

本文详细介绍了Hadoop中实现二次排序的方法,包括自定义键值类、分区器及分组比较器的过程。通过具体代码示例,展示了如何通过二次排序解决MapReduce任务中的复杂排序需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MapReduce框架对处理结果的输出会根据key值进行默认的排序,这个默认排序可以满足一部分需求。为了满足复杂的需求需要Hadoop二次排序Secondary Sort。

过程

在map阶段,使用job.setInputFormatClass定义的InputFormat将输入的数据集分割成小数据块splites,同时InputFormat提供一个RecordReder的实现。
他提供的RecordReder会将文本的一行的行号作为key,这一行的文本作为value。这就是自定义Map的输入是

流程

参考:http://zengzhaozheng.blog.51cto.com/8219051/1379271/

map:
每一条记录开始是进入到map函数进行处理,处理完了之后立马就入自定义分区函数中对其进行分区,当所有输入数据经过map函数和分区函数处理完之后,
就调用自定义二次排序函数对其进行排序。
reducer:
就是分组和reduce函数处理都是在shuffle完成之后才进行的。另外一点我们也非常容易看出,就是每处理完一个分组数据就会去调用一次的reduce函对这个分组来进行处理和输出。
此外,说明一下分组函数的返回值问题,当返回值为0时候才会被分到同一个组当中。另外一点我们也可以看出来,一个分组中每合并n个值就会有n-1分组函数返回0值,
也就是说有进行了n-1次比较。

实例

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.io.WritableComparator;
import org.apache.hadoop.mapreduce.Partitioner;

/**
 * 二次排序对象
 */
public class SortAssist {

    public static class UnionKey implements WritableComparable<UnionKey> {

        public String partitionerKey;

        public String resortString;

        public String getPartitionerKey() {
            return partitionerKey;
        }

        public void setPartitionerKey(String partitionerKey) {
            this.partitionerKey = partitionerKey;
        }

        public String getResortString() {
            return resortString;
        }

        public void setResortString(String resortString) {
            this.resortString = resortString;
        }

        @Override
        public void write(DataOutput out) throws IOException {
            out.writeUTF(partitionerKey);
            out.writeUTF(resortString);
        }

        @Override
        public void readFields(DataInput in) throws IOException {
            partitionerKey = in.readUTF();
            resortString = in.readUTF();
        }

        @Override
        public int hashCode() {
            return partitionerKey.hashCode() * 157 + resortString.hashCode();
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null)
                return false;
            if (this == obj)
                return true;
            if (obj instanceof UnionKey) {
                UnionKey r = (UnionKey) obj;
                return r.partitionerKey.equals(partitionerKey) && r.resortString.equals(resortString);
            } else {
                return false;
            }
        }
        //自定义比较器
        @Override
        public int compareTo(UnionKey o) {
            //确保进行排序的数据在同一个区内,如果不在同一个区则按照组合键中第一个键排序
            if (!partitionerKey.equals(o.partitionerKey)) {
                return partitionerKey.compareTo(o.partitionerKey);
            } else if (resortString != o.resortString) {
                //相同区内按照组合键的第二个键的升序排序
                return resortString.compareTo(o.resortString);
            } else
                return 0;
        }
    }

    //自定义分区处理器
    public static class SelfPartitioner extends Partitioner<UnionKey, Text> {

        @Override
        public int getPartition(UnionKey key, Text value, int numPartitions) {
            return Math.abs(key.partitionerKey.hashCode() * 127) % numPartitions;
        }

    }

    //自定义分区策略
    public static class SelfGroupingComparator extends WritableComparator {
        protected SelfGroupingComparator() {
            super(UnionKey.class, true);
        }

        @SuppressWarnings("rawtypes")
        public int compare(WritableComparable writableComparable, WritableComparable writableComparable2) {
            UnionKey unionKey = (UnionKey) writableComparable;
            UnionKey unionKey2 = (UnionKey) writableComparable2;
            String key1 = unionKey.getPartitionerKey();
            String key2 = unionKey2.getPartitionerKey();
            return key1.compareTo(key2);
        }
    }
}

job中调用

    job.setPartitionerClass(SortAssist.SelfPartitioner.class); //自定义分组器
    job.setGroupingComparatorClass(SortAssist.SelfGroupingComparator.class);  //自定义分区策略
### Hadoop 自带示例程序及其使用方法 Hadoop 提供了一系列内置的示例程序,主要用于验证集群配置以及帮助开发者熟悉 MapReduce 编程模型。以下是常见的 Hadoop 自带示例程序列表及它们的使用方法。 #### 常见的 Hadoop 示例程序 1. **WordCount**: 统计文本文件中单词的数量。 2. **Grep**: 计算匹配特定正则表达式的记录数。 3. **PiEstimator**: 使用蒙特卡罗方法估算圆周率 π 的值。 4. **TeraSort**: 测试大规模数据排序性能的一个基准工具。 5. **RandomWriter**: 随机写入大量数据到分布式文件系统 (DFS) 中用于压力测试。 6. **SecondarySort**: 实现二次排序功能,通常作为高级编程技巧展示。 7. **DBInputFormat 和 DBOutputFormat**: 将关系型数据库中的表读取出来或者把处理后的结果存回数据库。 以上列举的是部分典型应用案例[^1],实际可能因版本不同而有所差异。 #### 如何找到这些样本? 对于大多数标准发行版而言,默认情况下会随附 `hadoop-mapreduce-examples` JAR 文件,其中包含了上述各类实用范例代码片段。具体位置取决于安装方式与路径设置;例如,在某些环境中可以发现如下形式命名的包: ``` /usr/local/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-<version>.jar ``` 如果采用 Cloudera CDH 版本,则其存储地址类似于下面这样[^2]: ``` /opt/cloudera/parcels/CDH-x.y.z-p.q.r/lib/hadoop-0.20-mapreduce/hadoop-examples*.jar ``` #### 执行 WordCount 示例的具体操作流程 假设已经成功搭建好单节点或多节点模式下的 Hadoop 平台,并完成了必要的初始化工作之后,按照以下步骤来调用预定义好的 WordCount 功能: 1. 创建一个新的目录结构用来存放待分析的数据集以及最终产生的统计成果; ```bash hadoop fs -mkdir -p /user/<your_username>/input ``` 2. 把准备完毕的目标文档放置于此新建立起来的位置之下; ```bash hadoop fs -put local_path_to_file /user/<your_username>/input/ ``` 3. 启动计算进程本身——指定所使用的算法名称连同相应的参数选项一起传递给命令行解释器; ```bash hadoop jar path/to/hadoop-mapreduce-examples-<version>.jar wordcount input output ``` 这里需要注意替换掉 `<your_username>` 变量的实际用户名称还有确切版本号信息等内容项以便适配各自具体的场景需求情况[^3]. 通过这样的过程即可顺利完成整个端到端的任务执行周期演示效果观察体验啦! ```python # Python 脚本仅作示意用途,不参与本次讨论范围内的实现细节描述 print("This is just an example of how to run a job.") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值