`
qindongliang1922
  • 浏览: 2188634 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
7265517b-f87e-3137-b62c-5c6e30e26109
证道Lucene4
浏览量:117663
097be4a0-491e-39c0-89ff-3456fadf8262
证道Hadoop
浏览量:126070
41c37529-f6d8-32e4-8563-3b42b2712a50
证道shell编程
浏览量:60029
43832365-bc15-3f5d-b3cd-c9161722a70c
ELK修真
浏览量:71399
社区版块
存档分类
最新评论

如何使用Hadoop的Partitioner

阅读更多
Hadoop里面的MapReduce编程模型,非常灵活,大部分环节我们都可以重写它的API,来灵活定制我们自己的一些特殊需求。

今天散仙要说的这个分区函数Partitioner,也是一样如此,下面我们先来看下Partitioner的作用:
对map端输出的数据key作一个散列,使数据能够均匀分布在各个reduce上进行后续操作,避免产生热点区。
Hadoop默认使用的分区函数是Hash Partitioner,源码如下:

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.hadoop.mapreduce.lib.partition;

import org.apache.hadoop.mapreduce.Partitioner;

/** Partition keys by their {@link Object#hashCode()}. */
public class HashPartitioner<K, V> extends Partitioner<K, V> {

  /** Use {@link Object#hashCode()} to partition. */
  public int getPartition(K key, V value,
                          int numReduceTasks) {
	  //默认使用key的hash值与上int的最大值,避免出现数据溢出 的情况
    return (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks;
  }

}

大部分情况下,我们都会使用默认的分区函数,但有时我们又有一些,特殊的需求,而需要定制Partition来完成我们的业务,案例如下:
对如下数据,按字符串的长度分区,长度为1的放在一个,2的一个,3的各一个。

河南省;1
河南;2
中国;3
中国人;4
大;1
小;3
中;11

这时候,我们使用默认的分区函数,就不行了,所以需要我们定制自己的Partition,首先分析下,我们需要3个分区输出,所以在设置reduce的个数时,一定要设置为3,其次在partition里,进行分区时,要根据长度具体分区,而不是根据字符串的hash码来分区。核心代码如下:
	/**
	 * Partitioner
	 * 
	 * 
	 * */
	 public static class PPartition extends Partitioner<Text, Text>{ 
		@Override
		public int getPartition(Text arg0, Text arg1, int arg2) {
			 /**
			  * 自定义分区,实现长度不同的字符串,分到不同的reduce里面
			  * 
			  * 现在只有3个长度的字符串,所以可以把reduce的个数设置为3
			  * 有几个分区,就设置为几
			  * */
			
			String key=arg0.toString();
			if(key.length()==1){
				return 1%arg2;
			}else if(key.length()==2){
				return 2%arg2;
			}else if(key.length()==3){
				return 3%arg2;
			}
			
			  
			
			return  0;
		}
		 
		 
		 
		 
	 }


全部代码如下:
package com.partition.test;

import java.io.IOException;

import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Partitioner;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.db.DBConfiguration;
import org.apache.hadoop.mapreduce.lib.db.DBInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.MultipleOutputs;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;

import com.qin.operadb.PersonRecoder;
import com.qin.operadb.ReadMapDB;
 

/**
 * @author qindongliang
 * 
 * 大数据交流群:376932160
 * 
 * 
 * **/
public class MyTestPartition {
	
	/**
	 * map任务
	 * 
	 * */
	public static class PMapper extends Mapper<LongWritable, Text, Text, Text>{
			
		@Override
		protected void map(LongWritable key, Text value,Context context)
				throws IOException, InterruptedException {
			// System.out.println("进map了");
			//mos.write(namedOutput, key, value);
			String ss[]=value.toString().split(";");
			
			context.write(new Text(ss[0]), new Text(ss[1]));
			
			
			
		}
		
		
	}
	
	/**
	 * Partitioner
	 * 
	 * 
	 * */
	 public static class PPartition extends Partitioner<Text, Text>{ 
		@Override
		public int getPartition(Text arg0, Text arg1, int arg2) {
			 /**
			  * 自定义分区,实现长度不同的字符串,分到不同的reduce里面
			  * 
			  * 现在只有3个长度的字符串,所以可以把reduce的个数设置为3
			  * 有几个分区,就设置为几
			  * */
			
			String key=arg0.toString();
			if(key.length()==1){
				return 1%arg2;
			}else if(key.length()==2){
				return 2%arg2;
			}else if(key.length()==3){
				return 3%arg2;
			}
			
			  
			
			return  0;
		}
		 
		 
		 
		 
	 }
	 
 
	 /***
	  * Reduce任务
	  * 
	  * **/
	 public static class PReduce extends Reducer<Text, Text, Text, Text>{
		 @Override
		protected void reduce(Text arg0, Iterable<Text> arg1, Context arg2)
				throws IOException, InterruptedException {
			 
			  String key=arg0.toString().split(",")[0];
			 System.out.println("key==> "+key);
			 for(Text t:arg1){
				 //System.out.println("Reduce:  "+arg0.toString()+"   "+t.toString());
				 arg2.write(arg0, t);
			 }
			   
			 
		}
		 
	 
		 
	 }
	 
	 
	 public static void main(String[] args) throws Exception{
		 JobConf conf=new JobConf(ReadMapDB.class);
		 //Configuration conf=new Configuration();
	  	 conf.set("mapred.job.tracker","192.168.75.130:9001");
		//读取person中的数据字段
	  	 conf.setJar("tt.jar");
		//注意这行代码放在最前面,进行初始化,否则会报
	 
	 
		/**Job任务**/
		Job job=new Job(conf, "testpartion");
		job.setJarByClass(MyTestPartition.class);
		System.out.println("模式:  "+conf.get("mapred.job.tracker"));;
		// job.setCombinerClass(PCombine.class);
		 job.setPartitionerClass(PPartition.class);
		 
		 job.setNumReduceTasks(3);//设置为3
		 job.setMapperClass(PMapper.class);
		// MultipleOutputs.addNamedOutput(job, "hebei", TextOutputFormat.class, Text.class, Text.class);
		// MultipleOutputs.addNamedOutput(job, "henan", TextOutputFormat.class, Text.class, Text.class);
		 job.setReducerClass(PReduce.class);
		 job.setOutputKeyClass(Text.class);
		 job.setOutputValueClass(Text.class);
	    
		String path="hdfs://192.168.75.130:9000/root/outputdb";
		FileSystem fs=FileSystem.get(conf);
		Path p=new Path(path);
		if(fs.exists(p)){
			fs.delete(p, true);
			System.out.println("输出路径存在,已删除!");
		}
		FileInputFormat.setInputPaths(job, "hdfs://192.168.75.130:9000/root/input");
		FileOutputFormat.setOutputPath(job,p );
		System.exit(job.waitForCompletion(true) ? 0 : 1);  
		 
		 
	}
	
	

}

运行情况如下:

模式:  192.168.75.130:9001
输出路径存在,已删除!
WARN - JobClient.copyAndConfigureFiles(746) | Use GenericOptionsParser for parsing the arguments. Applications should implement Tool for the same.
INFO - FileInputFormat.listStatus(237) | Total input paths to process : 1
WARN - NativeCodeLoader.<clinit>(52) | Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
WARN - LoadSnappy.<clinit>(46) | Snappy native library not loaded
INFO - JobClient.monitorAndPrintJob(1380) | Running job: job_201404101853_0005
INFO - JobClient.monitorAndPrintJob(1393) |  map 0% reduce 0%
INFO - JobClient.monitorAndPrintJob(1393) |  map 100% reduce 0%
INFO - JobClient.monitorAndPrintJob(1393) |  map 100% reduce 11%
INFO - JobClient.monitorAndPrintJob(1393) |  map 100% reduce 22%
INFO - JobClient.monitorAndPrintJob(1393) |  map 100% reduce 55%
INFO - JobClient.monitorAndPrintJob(1393) |  map 100% reduce 100%
INFO - JobClient.monitorAndPrintJob(1448) | Job complete: job_201404101853_0005
INFO - Counters.log(585) | Counters: 29
INFO - Counters.log(587) |   Job Counters 
INFO - Counters.log(589) |     Launched reduce tasks=3
INFO - Counters.log(589) |     SLOTS_MILLIS_MAPS=7422
INFO - Counters.log(589) |     Total time spent by all reduces waiting after reserving slots (ms)=0
INFO - Counters.log(589) |     Total time spent by all maps waiting after reserving slots (ms)=0
INFO - Counters.log(589) |     Launched map tasks=1
INFO - Counters.log(589) |     Data-local map tasks=1
INFO - Counters.log(589) |     SLOTS_MILLIS_REDUCES=30036
INFO - Counters.log(587) |   File Output Format Counters 
INFO - Counters.log(589) |     Bytes Written=61
INFO - Counters.log(587) |   FileSystemCounters
INFO - Counters.log(589) |     FILE_BYTES_READ=93
INFO - Counters.log(589) |     HDFS_BYTES_READ=179
INFO - Counters.log(589) |     FILE_BYTES_WRITTEN=218396
INFO - Counters.log(589) |     HDFS_BYTES_WRITTEN=61
INFO - Counters.log(587) |   File Input Format Counters 
INFO - Counters.log(589) |     Bytes Read=68
INFO - Counters.log(587) |   Map-Reduce Framework
INFO - Counters.log(589) |     Map output materialized bytes=93
INFO - Counters.log(589) |     Map input records=7
INFO - Counters.log(589) |     Reduce shuffle bytes=93
INFO - Counters.log(589) |     Spilled Records=14
INFO - Counters.log(589) |     Map output bytes=61
INFO - Counters.log(589) |     Total committed heap usage (bytes)=207491072
INFO - Counters.log(589) |     CPU time spent (ms)=2650
INFO - Counters.log(589) |     Combine input records=0
INFO - Counters.log(589) |     SPLIT_RAW_BYTES=111
INFO - Counters.log(589) |     Reduce input records=7
INFO - Counters.log(589) |     Reduce input groups=7
INFO - Counters.log(589) |     Combine output records=0
INFO - Counters.log(589) |     Physical memory (bytes) snapshot=422174720
INFO - Counters.log(589) |     Reduce output records=7
INFO - Counters.log(589) |     Virtual memory (bytes) snapshot=2935713792
INFO - Counters.log(589) |     Map output records=7

运行后的结果文件如下:


其中,part-r-000000里面的数据
中国人	4
河南省	1


其中,part-r-000001里面的数据
中	11
大	1
小	3



其中,part-r-000002里面的数据
中国	3
河南	2

至此,我们使用自定义的分区策略完美的实现了,数据分区了。


总结:引用一段话

   (Partition)分区出现的必要性,如何使用Hadoop产生一个全局排序的文件?最简单的方法就是使用一个分区,但是该方法在处理大型文件时效率极低,因为一台机器必须处理所有输出文件,从而完全丧失了MapReduce所提供的并行架构的优势。事实上我们可以这样做,首先创建一系列排好序的文件;其次,串联这些文件(类似于归并排序);最后得到一个全局有序的文件。主要的思路是使用一个partitioner来描述全局排序的输出。比方说我们有1000个1-10000的数据,跑10个ruduce任务, 如果我们运行进行partition的时候,能够将在1-1000中数据的分配到第一个reduce中,1001-2000的数据分配到第二个reduce中,以此类推。即第n个reduce所分配到的数据全部大于第n-1个reduce中的数据。这样,每个reduce出来之后都是有序的了,我们只要cat所有的输出文件,变成一个大的文件,就都是有序的了

基本思路就是这样,但是现在有一个问题,就是数据的区间如何划分,在数据量大,还有我们并不清楚数据分布的情况下。一个比较简单的方法就是采样,假如有一亿的数据,我们可以对数据进行采样,如取10000个数据采样,然后对采样数据分区间。在Hadoop中,patition我们可以用TotalOrderPartitioner替换默认的分区。然后将采样的结果传给他,就可以实现我们想要的分区。在采样时,我们可以使用hadoop的几种采样工具,RandomSampler,InputSampler,IntervalSampler。

       这样,我们就可以对利用分布式文件系统进行大数据量的排序了,我们也可以重写Partitioner类中的compare函数,来定义比较的规则,从而可以实现字符串或其他非数字类型的排序,也可以实现二次排序乃至多次排序。


  • 大小: 57.1 KB
分享到:
评论

相关推荐

    Hadoop 自定义 Partitioner JAR

    Hadoop 自定义 Partitioner 实现

    Hadoop 自定义 Partitioner 实现

    Hadoop 自定义 Partitioner 实现

    Hadoop 自定义 Partitioner 源代码

    在分布式计算领域,Hadoop 是一个广泛使用的开源框架,它为大数据处理提供了高效、可靠的解决方案。其中,Partitioner 是 Hadoop MapReduce 框架中的关键组件,它负责决定 map 函数产生的中间键值对(key-value ...

    Partitioner, SortComparator and GroupingComparator in Hadoop

    在Hadoop MapReduce框架中,Partitioner、SortComparator和GroupingComparator是三个至关重要的组件,它们共同决定了数据如何被分发、排序以及分组,从而影响到整个MapReduce作业的性能和结果的正确性。接下来,我们...

    Partitioner.zip

    这个名为"Partitioner.zip"的压缩包很可能包含了关于Hadoop MapReduce Partitioner的相关资料或实现代码。 Partitioner在Hadoop MapReduce的工作流程中主要负责将Map阶段产生的中间键值对分发到各个Reduce任务中去...

    Hadoop命令使用手册中文版

    ### Hadoop命令使用手册中文版知识点详解 #### 一、Hadoop概述 Hadoop是一款开源软件框架,主要用于处理大规模数据集(通常在集群环境中)。它能够高效地存储和处理非常大的数据集,使得用户能够在相对较低成本的...

    Hadoop Real-World Solutions Cookbook 源代码

    5. **Chap 6 - 数据分析与挖掘**:此章节可能深入到使用Hadoop进行数据分析和挖掘,包括使用Mahout库进行机器学习,或者使用Spark进行实时流处理。 6. **Chap 7 - 高级MapReduce技术**:涵盖如使用Secondary Sort...

    Hadoop权威指南中文版(第二版)+Hadoop in Action

    4. **MapReduce编程**:理解Map函数和Reduce函数的实现,以及Combiner、Partitioner和Reducer的角色。编写Java MapReduce程序,并学习如何优化性能,如使用CombineReducer和本地化数据处理。 5. **HDFS操作**:文件...

    hadoop 文档:Hadoop开发者下载

    4. **Hadoop API**:学习使用Hadoop API进行数据读写和处理,例如FileSystem API用于文件操作,InputFormat和OutputFormat定义输入输出格式,Mapper和Reducer实现数据处理逻辑。 5. **MapReduce编程**:理解...

    hadoop使用

    【Hadoop使用】知识点详解 Hadoop是Apache软件基金会开发的一个开源分布式计算框架,它允许在廉价硬件上处理大规模数据。Hadoop的核心组件包括Hadoop Distributed File System (HDFS)和MapReduce。以下是对Hadoop...

    Hadoop-0.20.1+API

    3. **MapReduce API**:掌握如何编写Mapper和Reducer类,理解InputFormat、OutputFormat以及Partitioner的工作原理,以及JobConf配置的使用。 4. **Hadoop配置**:了解如何通过XML配置文件设置Hadoop集群参数,例如...

    实战hadoop中的源码

    7. **扩展性与插件开发**:学习如何为Hadoop开发自定义InputFormat、OutputFormat、Partitioner、Combiner等组件。 8. **实战项目**:结合实际案例,运用所学知识解决大数据处理问题,如日志分析、推荐系统等。 ...

    hadoop2.7.7src包

    同时,MapReduce的编程模型,如Mapper、Reducer、Partitioner、Combiner等,都在这个版本的源码中体现。 3. **YARN**:YARN是Hadoop 2.x引入的重要变化,它将资源管理和任务调度从MapReduce中分离出来,使得Hadoop...

    Hadoop实现大矩阵乘法

    本主题聚焦于如何使用Hadoop实现大矩阵乘法,这是一个在计算机科学和数据分析中常见的运算,特别是在机器学习和数值计算中。在Hadoop上实现大矩阵乘法,可以充分利用其并行计算的优势,提高计算效率。 大矩阵乘法的...

    实战hadoop源代码

    2. **HDFS操作**:源码可能包含使用HDFS API进行文件上传、下载、删除和检查等操作的示例,这些操作对于理解和使用Hadoop至关重要。 3. **MapReduce编程**:书中的例子会展示如何编写Map和Reduce函数,处理各种类型...

    Hadoop - Hadoop Streaming

    $ hadoop jar hadoop-streaming.jar -partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner -mapper mymapper -reducer myreducer -input input -output output ``` 这里 `org.apache.hadoop.mapred...

    hadoop-3.1.3.tar.gz编译后的源码包

    3. **hadoop-mapreduce-client**: 提供了MapReduce编程接口,包括JobClient、Mapper、Reducer和Partitioner等类。 4. **hadoop-yarn**: YARN(Yet Another Resource Negotiator)是Hadoop的资源管理系统,负责集群...

    hadoop课后题带答案

    10. Partitioner:Partitioner的作用是将key均匀分布到不同的ReduceTask上,以优化并行计算。 11. Zookeeper角色:Zookeeper集群包含Leader、Follower和Observer三种角色,用于分布式协调。 12. Znode类型:...

    hadoop的java_api

    9. **Hadoop配置**:在使用Hadoop Java API时,通常需要通过`Configuration`对象设置参数,如HDFS的地址、MapReduce的配置信息等。 10. **Hadoop客户端**:在Hadoop 2.x中,客户端库包含了一组API,用于与Hadoop...

    hadoop2.7.3源码包,hadoop2.7.3zip源码包

    同时,源码包也方便了开发者进行扩展和优化,例如自定义InputFormat、OutputFormat、Partitioner、Reducer等,以适应特定的业务需求。 此外,由于这个源码包是基于Maven结构生成的,所以它应该包含了所有依赖项的...

Global site tag (gtag.js) - Google Analytics