標籤:
一:背景
很多資料來源中的資料都是含有大量重複的,為此我們需要將重複的資料去掉,這也稱為資料的清洗,MapReduce從Map端到Reduce端的Shuffle過程天生就有去重的功能,但是這是對輸出的Key作為參照進行去重的。所以我們可以將Map端讀入Value作為Key輸出,就可以很方便的實現去重了。
二:技術實現
#需求 有兩個檔案file0和file1。將兩個檔案中的內容合并去重。
#file0的內容如下:
[java] view plain copy
- 1
- 1
- 2
- 2
- 3
- 3
- 4
- 4
- 5
- 5
- 6
- 6
- 7
- 8
- 9
file1的內容如下:
[java] view plain copy
- 1
- 9
- 9
- 8
- 8
- 7
- 7
- 6
- 6
- 5
- 5
- 4
- 4
- 2
- 1
- 2
代碼實現:
[java] view plain copy
- public class DistinctTest {
- // 定義輸入路徑
- private static final String INPUT_PATH = "hdfs://liaozhongmin:9000/distinct_file/*";
- // 定義輸出路徑
- private static final String OUT_PATH = "hdfs://liaozhongmin:9000/out";
-
- public static void main(String[] args) {
-
- try {
- // 建立配置資訊
- Configuration conf = new Configuration();
-
-
- // 建立檔案系統
- FileSystem fileSystem = FileSystem.get(new URI(OUT_PATH), conf);
- // 如果輸出目錄存在,我們就刪除
- if (fileSystem.exists(new Path(OUT_PATH))) {
- fileSystem.delete(new Path(OUT_PATH), true);
- }
-
- // 建立任務
- Job job = new Job(conf, DistinctTest.class.getName());
-
- //1.1 設定輸入目錄和設定輸入資料格式化的類
- FileInputFormat.setInputPaths(job, INPUT_PATH);
- job.setInputFormatClass(TextInputFormat.class);
-
- //1.2 設定自訂Mapper類和設定map函數輸出資料的key和value的類型
- job.setMapperClass(DistinctMapper.class);
- job.setMapOutputKeyClass(Text.class);
- job.setMapOutputValueClass(Text.class);
-
- //1.3 設定分區和reduce數量(reduce的數量,和分區的數量對應,因為分區為一個,所以reduce的數量也是一個)
- job.setPartitionerClass(HashPartitioner.class);
- job.setNumReduceTasks(1);
-
- //1.4 排序
- //1.5 歸約
- job.setCombinerClass(DistinctReducer.class);
- //2.1 Shuffle把資料從Map端拷貝到Reduce端。
- //2.2 指定Reducer類和輸出key和value的類型
- job.setReducerClass(DistinctReducer.class);
- job.setOutputKeyClass(Text.class);
- job.setOutputValueClass(Text.class);
-
- //2.3 指定輸出的路徑和設定輸出的格式化類
- FileOutputFormat.setOutputPath(job, new Path(OUT_PATH));
- job.setOutputFormatClass(TextOutputFormat.class);
-
-
- // 提交作業 退出
- System.exit(job.waitForCompletion(true) ? 0 : 1);
-
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- public static class DistinctMapper extends Mapper<LongWritable, Text, Text, Text>{
- //定義寫出去的key和value
- private Text outKey = new Text();
- private Text outValue = new Text("");
- @Override
- protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, Text>.Context context) throws IOException, InterruptedException {
- //把輸入的key作為value輸出(因為)
- outKey = value;
-
- //把結果寫出去
- context.write(outKey, outValue);
- }
- }
-
- public static class DistinctReducer extends Reducer<Text, Text, Text, Text>{
- @Override
- protected void reduce(Text key, Iterable<Text> value, Reducer<Text, Text, Text, Text>.Context context) throws IOException, InterruptedException {
- //直接把key寫出去
- context.write(key, new Text(""));
- }
- }
- }
程式啟動並執行結果:
MapReduce去重