問題は
条件に応じて、統計結果を異なるファイル(パーティション)に出力する必要があります。例:携帯電話が属するさまざまな州に応じて、統計結果をさまざまなファイル(パーティション)に出力します
新入生<k、v>が学校に入学するのと同様に、さまざまな学生に寮が割り当てられ、さまざまな寮に入る(タスクを減らす)。マップによって送信されるデータの量が多すぎる場合、これらのデータはすべて次の場所に送られます。デフォルトのreduceノード。実行は並列コンピューティングを減らす目的を果たしておらず、IOプレッシャーも大きいです。これがパーティションの理由です。
デフォルトのパーティションは、キーのhashCodeに基づいてReduceタスクの数を調整することによって取得されます。ユーザーは、どのキーをどのパーティションに保存するかを制御できません。
パブリッククラスHashPartitioner <K、V>延びパーティショナ<K、V> {
|
a)デフォルトでゾーンを割り当てます
b)複数の領域を割り当てることは、いくつかのreduceタスクに対応し、各タスクは、実行時にreduceのコードを共有します。
c)カスタムパーティションの場合、返されるパーティションの数は、定義されたreduceタスクと同じである必要があります。具体的には、カスタムパーティションクラスはHashPartitionerを拡張し、getPartitionを書き換える場合、返されるブランチの数はjob.setNumReduceTasks(X)と同じである必要があります。 ; Xの数は同じです。
d)カスタムパーティションはカスタムパーティショナーPartitionerに依存する必要があります。動作原理は(図)に示すとおりです。図から、1つのパーティションにreduceが必要であり、各reduceは異なるパーティションの結果を処理して出力します。さまざまなパーツ-r--0000X。
場合:
携帯電話が属するさまざまな州に応じて、統計結果をさまざまなファイル(パーティション)にエクスポートします
(1)入力データ
(2)入力フォーマット
id mobile number network ipURLアップストリームトラフィックダウンストリームトラフィックネットワークステータスコード 1、13736230513、192.196.100.1、www.atguigu.com、 2481、24681、200 2、13845644121、192.196.100.2、、264、0、200 3、13956435636、192.196.100.3、、132、1512、200 4、13966251146、192.168.100.1、、240、0、404 |
- 期待される出力データ形式
137で始まるファイル
id mobile number network ipURLアップストリームトラフィックダウンストリームトラフィックネットワークステータスコード 1、13736230513、192.196.100.1、www.atguigu.com、 2481、24681、200 |
138で始まるファイル
id mobile number network ipURLアップストリームトラフィックダウンストリームトラフィックネットワークステータスコード 2、13845644121、192.196.100.2、、264、0、200 |
139で始まるファイル
id mobile number network ipURLアップストリームトラフィックダウンストリームトラフィックネットワークステータスコード 3、13956435636、192.196.100.3、、132、1512、200 4、13966251146、192.168.100.1、、240、0、404 |
アイデア:携帯電話番号がキーとして使用され、行の値が値として使用されます
(1)Mapreduceでは、マップによって出力されたkvペアが同じキーに従ってグループ化され、異なるreduceタスクに分散されます。デフォルトの配布ルールは次のとおりです。キーのhashcode%reducetask番号に従って配布します。
(2)独自のニーズに応じてグループ化する場合は、データ分散(グループ化)コンポーネントPartitionerを書き直す必要があります。
(3)カスタムパーティションを設定するFlowPartitionerは、抽象クラスPartitioneを継承し、携帯電話136の先頭に最初のreduceを配置して統計を完成させます。出力結果はパーティション番号0にあり、同じです。 137、138、139およびその他の結果のために配置されます。パーティション番号1〜4に。
(4 )getPartition()メソッドを介してmappperによって出力された結果のフィルター処理を開始し、2で設定された比較を介して異なるパーティション番号で出力します。
(5 )異なるreduceを介してパーティションデータを処理し、異なるpart-r-0000xに出力します。
(6 )カスタムパーティションクラスとタスク数をドライバークラスジョブに追加します。
job.setPartitionerClass(CustomPartitioner.class)
job.setNumReduceTasks(5)
FlowPartitioner.classを追加します
package hdfs_demo.partiyioner;
import hdfs_demo.telFlow.FlowBean;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Partitioner;
public class FlowPartitioner extends Partitioner<Text, FlowBean> {
/**
* 返回分区号
* @param text
* @param flowBean
* @param numPartitions
* @return
*/
//进行分区
public int getPartition(Text text, FlowBean flowBean, int numPartitions) {
String phone = text.toString();//获取手机号
switch (phone.substring(0,3)){
case "136":
return 0;
case "137":
return 1;
case "138":
return 2;
case "139":
return 3;
default:
return 4;
}
}
}
FlowDriver.classにパーティション設定を追加します。
package hdfs_demo.partiyioner;
import hdfs_demo.telFlow.FlowBean;
import hdfs_demo.telFlow.FlowMapper;
import hdfs_demo.telFlow.FlowReducer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
public class FlowDriver {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
//创建配置对象
Configuration conf = new Configuration();
//创建一个job对象
Job job = Job.getInstance(conf, "telFlowCount");
//mapreduce的启动类
job.setJarByClass(FlowDriver.class);
//设置mapper 和reducer
job.setMapperClass(FlowMapper.class);
job.setReducerClass(FlowReducer.class);
//设置map的输出类型 Text, FlowBean
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(FlowBean.class);
//设置reduce的输出类型 Text, FlowBean
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(FlowBean.class);
// 在驱动类job中添加自定义分区类和任务数量
job.setPartitionerClass(FlowPartitioner.class);
job.setNumReduceTasks(5);
//设置输入数据路径
FileInputFormat.setInputPaths(job, new Path("G:\\idea-workspace\\hdfs_java_api\\Resource\\telinfo.txt"));
//设置reducer输出结果的路径
FileOutputFormat.setOutputPath(job, new Path("G:\\idea-workspace\\hdfs_java_api\\Resource\\result"));
//提交任务
boolean b = job.waitForCompletion(true);
System.out.println(b);
}
}
並べ替えには、FlowBeanにcompareToメソッドを実装するだけで済みます。
public int compareTo(Object o) {
return 0;
}
}
public int compareTo(Object o) {
FlowBean bean =(FlowBean )o;
// 倒序排列,从大到小
return this.sumFlow>bean.getSumFlow() ? -1 : 1;
}