複習總結01:Hadoop

一、關於設置hdfs
①獲取hdfs文件系統
1
Configuration configuration = new Configuration();
2
FileSystem fSystem = fSystem = FileSystem.get(new URI("hdfs://server:9000"), configuration, "hadoop");
備註:拋出異常Exception;直接操作hdfs上的文件,需要輸入用戶名,而提交Job等不需要輸入用戶名。
或者Run Configuration 的Environment variables HADOOP_USER_NAME hadoop
②單元測試
@before  標識的函數 A---->對某函數B進行單元測試前必須先執行的函數A
@Test  被測試的函數 B

二、運行模式

/***********設定本地測試模式 輸入輸出文件,,在本地或者集羣*************/
1
        Configuration conf = new Configuration();
2
        Job job = Job.getInstance(conf);
3
4
        job.setJarByClass(WordCountDriver.class);
5
        job.setMapperClass(WordCountMapper.class);
6
        job.setReducerClass(WordCountReducer.class);
7
8
        job.setMapOutputKeyClass(Text.class);
9
        job.setMapOutputValueClass(IntWritable.class);
10
11
        job.setOutputKeyClass(Text.class);
12
        job.setOutputValueClass(IntWritable.class);
13
14
        //輸入輸出的文件都在本地,適合來測試代碼可靠性
15
        FileInputFormat.setInputPaths(job, new Path("d:/a.txt"));   //執行本地模式
16
        FileOutputFormat.setOutputPath(job, new Path("d:/a_out"));  //路徑必須是新的
17
        //將上兩句設置爲以下兩句即可 實現:輸入輸出的文件都在集羣,在本地運行,實際中大文件傳輸耗損!不能發揮雲計算的優點
18
        FileInputFormat.setInputPaths(job, new Path("hdfs://server:9000/a.txt"));
19
        FileOutputFormat.setOutputPath(job, new Path("hdfs://server:9000/aaaa_out"));
20
21
        boolean res = job.waitForCompletion(true);
22
        System.exit(res ? 0 : 1);
備註:本地運行時,可以不 設置Run Configuration 的Environment variables HADOOP_USER_NAME hadoop 也能正常運行。
(即本地運行,用戶可設置也可不設置)
只是文件的user name 是本機電腦的user_name 不是hadoop
/***********設定集羣運行模式 輸入輸出文件都在集羣*************/
方式A
將程序打成JAR包,然後在集羣的任意一個節點上用hadoop命令啓動 推薦
$ hadoop jar wordcount.jar cn.itcast.bigdata.mrsimple.WordCountDriver inputpath outputpath

方式B
修改YarnRunner,並且將四個配置文件放在src下。在執行時也需要打包放到linux上。
只是把控制檯的消息打印在了windows的IDEA上,實際意義不大,放棄!

故總結運行模式:①本地來測試代碼邏輯;②打包提交到集羣模式運行

三、Hadoop開發MapReduce框架用到的Java API
①TestMapper類繼承Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT>{}
1
KEYIN  :  LongWritable   //KEYIN: 默認情況下是mr框架所讀到的一行文本的起始偏移量。但是在hadoop中有自己的更精簡的序列化接口LongWritable(extends WritableComparable)
2
VALUEIN  :  Text    //讀取的一行數據String 原因同上故用Text
3
KEYOUT   :  Text    //用戶自定義輸出的數據格式key    一般用Text滿足序列化
4
VALUEOUT  : IntWritable   //用戶自定義輸出的數據value   一般輸出是個對象,算法中可能會用IntWritable(1);
實現方法A:protected void map(LongWritable key, Text value, Context context) throw Exception{} 
  //map階段的業務邏輯就寫在自定義的map()方法中,maptask會對每一行輸入數據調用一次自定義的map()方法。
  context.write(new Text(key) ,new IntWritable(value)) 無參數時用nullWritable

實現方法B:protected void setup(Context context ,)throws Exception{}     //task啓動的時候調用。
實現方法C:protected void cleanup(Context context ,)throws Exception{}  //task結束的時候調用。


② TextReducer類繼承 Reducer<KEYIN,VALUEIN,KEYOUT,VALUEOUT> {}類
1
KEYIN, VALUEIN    //對應  mapper輸出的KEYOUT,VALUEOUT類型對應
2
KEYOUT, VALUEOUT   //是自定義reduce邏輯處理結果的輸出數據類型一般是<Text,Bean>
實現方法A:protected void reduce(Text key, Iterable<IntWritable> values, Context contextthrows Exception {}類
  //按照key分組,確定reduceTask的個數。每個reduceTask都會執行此自定義的reduce()方法,對values進行迭代
  //如果key來傳過來的是對象, 每個對象都是不一樣的, 所以每個對象都調用一次reduce方法。
實現方法B:protected void setup(Context context ,)throws Exception{} //task啓動的時候調用。
實現方法C:protected void cleanup(Context context ,)throws Exception{} //task結束的時候調用。

③TextDriver類 執行main方法<完成九行設置,兩行IO,兩行等待結束>

……………………………………………………以上是標準MR程序的設計規範,以下補充一些常用的API…………………………………………………………………………

擴展API
①String[] values=value.toString().split("\t");//將讀取的第一行數據,按照字符串裏面內容分片.
數據表格:可將多重數據存在字符串中,然後再次利用split(",")方法取出各數據
判斷讀入的字符串是否非空         StringUtils.isNotEmpty(line)
檢測字符串相同與否用       .equals();
將字符串中的數字轉變成int型         Integer.parseInt(fields[0])
②StringBuffer:起到String沒有的功能      stringBuffer.append(variable).append(",");
③Text,IntWritable,LongWritable.  new Text("A");   new IntWritable(1);   new LongWritable();
④Iterable<T>接口,Iterator<T> iterator();用在reduce()方法直接寫出結果的情況。context.write(values.iterator().next(), bean);
在處理切片時,通過文件名區別讀入的切片
FileSplit inputSplit = (FileSplit) context.getInputSplit();//獲得輸入切片
String fileName = inputSplit.getPath().getName();//獲得切片的源文件名
⑥遍歷values: for(String value : values);
partitioner<key ,value>抽象類。繼承後重寫int getPartition(KEY key, VALUE valueint numPartitions);實現該方法,自定義某(k,v)對對應的reduceTask。
1
// 指定我們自定義的數據分區器
2
job.setPartitionerClass(ProvincePartitioner.class);
3
// 同時指定相應“分區”數量的reducetask
4
job.setNumReduceTasks(5);
構建ProvincePartitioner.class 繼承Partitioner 實現字段匹配分類
1
   public static HashMap<String, Integer> proviceDict = new HashMap<String, Integer>();
2
3
    static {
4
        proviceDict.put("136", 0);
5
        proviceDict.put("137", 1);
6
        proviceDict.put("138", 2);
7
        proviceDict.put("139", 3);
8
    }    
9
10
    String prefix = key.toString().substring(0, 3);  //根據字段,區分ID
11
    Integer provinceId = proviceDict.get(prefix);    //獲取ID
12
13
    return (provinceId == null) ? 4 : provinceId;    //返回ID


四、關於Map等集合:大數據處理中的(k,v)對,Java一定會用到Map。
Map用於保存具有映射關係的數據,因此Map集合裏保存着兩組值,K-V,Key不能重複。元素的Key索引從Map裏取出該元素
Map裏:所有Key放在一起來看==>一個Set集合。Value放在一起==>一個List。即 Map<Set , List>.
Map接口下有HashMap、LinkedHashMap、SortedMap、TreeMap、EnumMap。
1
Map常用方法:
2
void clear();    //刪除該Map對象的所有key-value對。
3
boolean containsKey(Object key);       //查詢Map中是否包含指定的key,如果包含則返回true。
4
boolean containsValue(Obejct,value);        //查詢Map中是否包含一個或多個Value,如果包含則返回true。
5
Set entrySet();返回Map中包含的key-value對所組成的Set集合,每個集合元素都是Map.Entry對象。
6
Object get(Object key);返回指定key所對應的value,如果此Map中不包含該key,則返回null。
7
boolean isEmpty();查詢該Map是否爲空。若空爲true。
8
Set keySet();    //返回該Map中所有key組成的Set集合。
9
Object put(Object key,Object value);     //添加一個key-value對。如果有則覆蓋。
10
void putAll(Map m);      //將m中的key-value對複製到本Map中。
11
Object remove(Object key);      //刪除指定key所對應的key-value對,返回被刪除key所關聯的value,如果沒有則返回null。
12
boolean remove(Object key,Object value);     //刪除指定k-v對。成功刪除則返回true,否則爲false。
13
int size();       //返回該Map裏的k-v對的個數。
14
Collection values();        //返回該Map裏所有value組成的Collection。
15
16
Map內部類Entry,該類封裝了k-v對,Entry包含三個方法:
17
Object getKey();返回該Entry裏包含的key值。
18
Object getValue();返回該Entry裏包含的value值。
19
Object setValue(V value);設置Entry裏包含的value值,並返回新設置的value。

五、關於MapReduce編程的整理與總結
mapreduce在編程的時候,基本上一個固化的模式,沒有太多可靈活改變的地方,除了以下幾處:
1、輸入數據接口:InputFormat   --->     FileInputFormat(文件類型數據讀取的通用抽象類)  DBInputFormat (數據庫數據讀取的通用抽象類)
   默認使用的實現類是: TextInputFormat     job.setInputFormatClass(TextInputFormat.class)
   TextInputFormat的功能邏輯是:一次讀一行文本,然後將該行的起始偏移量作爲key,行內容作爲value返回
   
2、邏輯處理接口: Mapper  
   完全需要用戶自己去實現其中  map()   setup()   clean()   
   
3、map輸出的結果在shuffle階段會被partition以及sort,此處有兩個接口可自定義:
Partitioner有默認實現 HashPartitioner,邏輯是  根據key和numReduces來返回一個分區號; key.hashCode()&Integer.MAXVALUE % numReduces。通常情況下,用默認的這個HashPartitioner就可以,如果業務上有特別的需求,可以自定義
Comparable當我們用自定義的對象作爲key來輸出時,就必須要實現WritableComparable接口,override其中的compareTo()方法

4、reduce端的數據分組比較接口 : Groupingcomparator reduceTask拿到輸入數據(一個partition的所有數據)後,首先需要對數據進行分組,其分組的默認原則是key相同,然後對每一組kv數據調用一次reduce()方法,並且將這一組kv中的第一個kv的key作爲參數傳給reduce的key,將這一組數據的value的迭代器傳給reduce()的values參數。
利用上述這個機制,我們可以實現一個高效的分組取最大值的邏輯:自定義一個bean對象用來封裝我們的數據,然後改寫其compareTo方法產生倒序排序的效果,然後自定義一個Groupingcomparator,將bean對象的分組邏輯改成按照我們的業務分組id來分組(比如訂單號)這樣,我們要取的最大值就是reduce()方法中傳進來key

5、邏輯處理接口:Reducer完全需要用戶自己去實現其中  reduce()   setup()   clean()   

6、輸出數據接口: OutputFormat  ---> 有一系列子類  FileOutputformat  DBoutputFormat  .....默認實現類是TextOutputFormat,功能邏輯是:  將每一個KV對向目標文本文件中輸出爲一行



六、MR框架編程要點:
詳見eclipse的Test模板包
手機號的流量數據分析:

①從hdfs上獲取文件的手機號及其流量統計的數據
②輸出結果按照流量大小排序
③輸出結果按照省份分割數據到不同的文件

一、項目分析:
①對hdfs上的數據格式分析,確定(k,v)手機號來做key;上下行數據量構成對象做value。
②構造對象Bean,成員變量及其方法。
③編寫Mapper和Reducer類及方法

1、完成Bean的對象構造
①根據對象特點,完善其成員變量以及其get(),set()方法;
②因爲要使用context.write(k,v)所以對象要實現Writable的接口;實現後即可以被寫
③實現String toString();方法。
備註:如果作爲對象的模板學會 修改成員變量;

2、編寫Mapper類(在TestMR類中寫靜態mapper類)
①:繼承Mapper確定輸入輸出的數據格式;
②:讀取一行內容,用空格"\t"或者某些標識切割一行數據,獲取內容存儲在字符串數組中;
③:數據解析後構造對象,寫入context。

3、編寫Reducer類(在TestMR類中寫靜態reducer類)
①確定輸入輸出kv對與Mapper輸出的kv對格式相同;
②按照key完成Values的遍歷,迭代等操作;
③輸出結果文件,注意輸出的對象的定義,最後封裝對象輸出。

4、編寫Driver類(一般在TestMR類中寫main方法實現)
①設定Job;
②完成一系列的設置,類,輸入輸出格式,文件路徑;
③提交Job,檢測。

5、提交Job,進行雲計算
①打包jar,sftp提交到host上;
②執行 hadoop jar Test.jar test.TestMR
③執行 hadoop fs -cat /output/part-r-00000 讀取結果文件







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章