一、問題背景
實際業務的需要,比如以移動為例,河南的用戶去了北京上網,那么他的上網信息默認保存在了北京的基站,那么我們想要查詢北京地區的上網日志信息默認也包含了其他地區用戶的在本區的上網信息,否則只能掃描日志找到北京,很慢,所以分區很需要。
二、數據集分析
1363157985066 13726230503 00-FD-07-A4-72-B8:CMCC 120.196.100.82 i02.c.aliimg.com 24 27 2481 24681 200
1363157995052 13826544101 5C-0E-8B-C7-F1-E0:CMCC 120.197.40.4 4 0 264 0 200
1363157991076 13926435656 20-10-7A-28-CC-0A:CMCC 120.196.100.99 2 4 132 1512 200
1363154400022 13926251106 5C-0E-8B-8B-B1-50:CMCC 120.197.40.4 4 0 240 0 200
1363157993044 18211575961 94-71-AC-CD-E6-18:CMCC-EASY 120.196.100.99 iface.qiyi.com 視頻網站 15 12 1527 2106 200
1363157995074 84138413 5C-0E-8B-8C-E8-20:7DaysInn 120.197.40.4 122.72.52.12 20 16 4116 1432 200
1363157993055 13560439658 C4-17-FE-BA-DE-D9:CMCC 120.196.100.99 18 15 1116 954 200
1363157995033 15920133257 5C-0E-8B-C7-BA-20:CMCC 120.197.40.4 sug.so.360.cn 信息安全 20 20 3156 2936 200
1363157983019 13719199419 68-A1-B7-03-07-B1:CMCC-EASY 120.196.100.82 4 0 240 0 200
1363157984041 13660577991 5C-0E-8B-92-5C-20:CMCC-EASY 120.197.40.4 s19.cnzz.com 站點統計 24 9 6960 690 200
1363157973098 15013685858 5C-0E-8B-C7-F7-90:CMCC 120.197.40.4 rank.ie.sogou.com 搜索引擎 28 27 3659 3538 200
1363157986029 15989002119 E8-99-C4-4E-93-E0:CMCC-EASY 120.196.100.99 www.umeng.com 站點統計 3 3 1938 180 200
1363157992093 13560439658 C4-17-FE-BA-DE-D9:CMCC 120.196.100.99 15 9 918 4938 200
1363157986041 13480253104 5C-0E-8B-C7-FC-80:CMCC-EASY 120.197.40.4 3 3 180 180 200
1363157984040 13602846565 5C-0E-8B-8B-B6-00:CMCC 120.197.40.4 2052.flash2-http.qq.com 綜合門戶 15 12 1938 2910 200
1363157995093 13922314466 00-FD-07-A2-EC-BA:CMCC 120.196.100.82 img.qfc.cn 12 12 3008 3720 200
1363157982040 13502468823 5C-0A-5B-6A-0B-D4:CMCC-EASY 120.196.100.99 y0.ifengimg.com 綜合門戶 57 102 7335 110349 200
1363157986072 18320173382 84-25-DB-4F-10-1A:CMCC-EASY 120.196.100.99 input.shouji.sogou.com 搜索引擎 21 18 9531 2412 200
1363157990043 13925057413 00-1F-64-E1-E6-9A:CMCC 120.196.100.55 t3.baidu.com 搜索引擎 69 63 11058 48243 200
1363157988072 13760778710 00-FD-07-A4-7B-08:CMCC 120.196.100.82 2 2 120 120 200
1363157985066 13726238888 00-FD-07-A4-72-B8:CMCC 120.196.100.82 i02.c.aliimg.com 24 27 2481 24681 200
1363157993055 13560436666 C4-17-FE-BA-DE-D9:CMCC 120.196.100.99 18 15 1116 954 200
查看電話號碼一列,看前三位分為移動、聯通和電信,不過還有以84開頭的同意歸屬為海外,那么我們需要的共有4個reducer,那么需要Partitioner里面需要自己分為四類。
一個reducer對應一個結果文件。
不能再本地運行,這樣的話只能一個map,一個reducer,無論設置。
三、理論準備
3.1 抽象類與接口
? 我們都知道在面向對象的領域一切都是對象,同時所有的對象都是通過類來描述的,但是并不是所有的類都是來描述對象的。如果一個類沒有足夠的信息來描述一個具體的對象,而需要其他具體的類來支撐它,那么這樣的類我們稱它為抽象類。比如new Animal(),我們都知道這個是產生一個動物Animal對象,但是這個Animal具體長成什么樣子我們并不知道,它沒有一個具體動物的概念,所以他就是一個抽象類,需要一個具體的動物,如狗、貓來對它進行特定的描述,我們才知道它長成啥樣。
抽象類和普通類的區別是強制讓子類去重寫弗雷的方法。
public abstract class Animal { public abstract void cry();
} public class Cat extends Animal{ @Override public void cry() { System.out.println("貓叫:喵喵..."); }
} public class Dog extends Animal{ @Override public void cry() { System.out.println("狗叫:汪汪..."); } } public class Test { public static void main(String[] args) { Animal a1 = new Cat(); Animal a2 = new Dog(); a1.cry(); a2.cry(); }
} --------------------------------------------------------------------
Output:
貓叫:喵喵...
狗叫:汪汪...
抽象層次不同。抽象類是對類抽象,而接口是對行為的抽象。抽象類是對整個類整體進行抽象,包括屬性、行為,但是接口卻是對類局部(行為)進行抽象。
? ? ?抽象類所跨域的是具有相似特點的類,而接口卻可以跨域不同的類。我們知道抽象類是從子類中發現公共部分,然后泛化成抽象類,子類繼承該父類即可,但是接口不同。實現它的子類可以不存在任何關系,共同之處。例如貓、狗可以抽象成一個動物類抽象類,具備叫的方法。鳥、飛機可以實現飛Fly接口,具備飛的行為,這里我們總不能將鳥、飛機共用一個父類吧!所以說抽象類所體現的是一種繼承關系,要想使得繼承關系合理,父類和派生類之間必須存在"is-a" 關系,即父類和派生類在概念本質上應該是相同的。對于接口則不然,并不要求接口的實現者和接口定義在概念本質上是一致的, 僅僅是實現了接口定義的契約而已。
3.2 static塊與單例
static塊會在實例初始化之前執行,所以你可以在方法調用之前進行一些初始化操作,
單例是獲取對象的一種方式而已,保證只有一個實現類,
實際開發中幾乎用不到,單例spring提供有實現,static在測試的時候可能會用到,還有加載一些系統配置文件的時候可能會把加載寫在static塊中。
四、代碼實現
//Partitioner是map執行完成后reduce還沒執行,所以他的類型是map的輸出類型
public class DataCountPartitioner extends Partitioner<Text,DataBean> {//沒執行一次變讀取一次數據庫很不好,可以做緩存,或者搞成單利,//為了簡單直接搞一個static塊private static Map<String , Integer> dataCountMap = new HashMap<String , Integer>();static {//靜態的從上往下執行,也就是先執行上面的datacoutnMap,否則靜態塊里//網datacountmap里棉放東西dataCountMap.put("135",1);dataCountMap.put("136",1);dataCountMap.put("137",1);dataCountMap.put("138",1);dataCountMap.put("139",1);dataCountMap.put("150",2);dataCountMap.put("159",2);dataCountMap.put("182",2);dataCountMap.put("183",2);}//int表示分區號//numPartitions:幾個reducer就有幾個這個值@Overridepublic int getPartition(Text key, DataBean value, int numPartitions) {// TODO Auto-generated method stubString telNo = key.toString();//從0開始取3位String subTelNo = telNo.substring(0, 3);Integer code = dataCountMap.get(subTelNo);//186 843等開頭的默認是國外if(null==code) {code = 0;}return code;}
}
五、結果分析
5.1 _SUCCESS
這個沒啥用,mapreduce自帶的,不過如果你的程序有多部mapreduce,肯定會有中間結果,那么倒是可以這個_success來判斷是否執行了上個步驟,也就是說在補數據的時候,如果發現某一步_success了?那么就說明上一步不用補跑mapreduce,直接執行下面的程序.
5.2 結果
查看結果發現0里面是134和841開頭的,達到預期,1和2分別是聯通,3是空的,為什么呢?因為partitioner里面的分類設置類3個,而reducer個數是4個,其中一個reducer沒有數據粉發過去所以就是空的。
那如果reducer個數小于partitioner個數呢,我發現輸出文件加油,也沒報錯,就是空文件夾。需要log4j才能看到報錯信息。
?