hadoop輸入路徑遇到的問題

在hadoop的編程中,若是你是手寫MapReduce來處理一些數據,那麼就避免不了輸入輸出參數路徑的設定,hadoop裏文件基類FileInputFormat提供了以下幾種api來制定: 

 


如上圖,裏面有 
(1)addInputPath(),每次添加一個輸入路徑Path 
(2)addInputPaths, 將多個路徑以逗號分割的字符串,做爲入參,支持多個路徑 
(3)setInputPath ,設置一個輸入路徑Path,會覆蓋原來的路徑 
(4)setInputPath , 設置多個路徑,支持Hadoop文件系統重寫的Path對象,這在JAVA裏是接口。 

代碼以下: 

 html

Java代碼   收藏代碼redis

  1. FileInputFormat.setInputDirRecursive(job, true);//設置能夠遞歸讀取目錄  
  2. FileInputFormat.addInputPath(job, new Path("path1"));  
  3. FileInputFormat.addInputPaths(job, "path1,path2,path3,path....");  
  4. FileInputFormat.setInputPaths(job, new Path("path1"),new Path("path2"));  
  5. FileInputFormat.setInputPaths(job, "path1,path2,path3,path....");  




而真正用的時候,咱們只須要根據業務使用上面的其中一個路徑便可。 
ok知道怎麼,傳入路徑了,下面來看下,如何在HDFS上過濾出,本身想要的文件或目錄,HDFS系統的路徑默認是支持正則過濾的,這一點很是強大,只要咱們會寫正則,咱們幾乎能夠過濾任何咱們想要的路徑或文件。 

詳細內容請查閱這個連接http://hadoop.apache.org/docs/current/api/org/apache/hadoop/fs/FileSystem.html#globStatus(org.apache.hadoop.fs.Path)
下面散仙就舉個實際項目應用中的例子,這樣能幫助你們更好的理解和使用它。 
先看下面的一個HDFS上的存儲結構圖: 


 



這是一個按日期天天生成的一個文件夾,固然這裏能夠有不少分維度的法,好比按照年,月,日,小時,來劃分,具體狀況應跟業務結合考慮。 

看下,直接的根目錄的下一級目錄: 

 


ok,存儲結構清楚了,那麼如今提幾個需求 

(1)只過濾出pv目錄下的數據 
(2)只過濾出uv目錄下的數據 
(3)只過濾出keyword目錄下的數據 
(4)只過濾出pv和uv的數據或者叫以v結尾的數據 
(5)過濾2015年的數據 
(6)過濾出某個時間範圍內的數據好比2015-04-10到2015-04-17時間範圍下的pv的數據 


其實前個需求很簡單都是一種需求: 

hadoop裏的FileStatus類是支持路徑通配的,對應的寫法以下: 



 apache

Java代碼   收藏代碼編程

  1. FileSystem fs = FileSystem.get(conf);  
  2. //  
  3. //過濾pv或uv的目錄數據  
  4.   String basepath="/user/d1/DataFileShare/Search/*/*/{pv,uv}";  
  5. //過濾v結尾的目錄數據  
  6.   String basepath="/user/d1/DataFileShare/Search//*/*/*v";  
  7. //過濾uv的數據  
  8.   String basepath="/user/d1/DataFileShare/Search//*/*/uv";  
  9. //過濾pv的數據  
  10.   String basepath="/user/d1/DataFileShare/Search//*/*/pv";  
  11.   
  12. //過濾2015年的pv的數據  
  13. String basepath="/user/d1/DataFileShare/Search/2015*/*/pv";    
  14. //獲取globStatus  
  15. FileStatus[] status = fs.globStatus(new Path(basepath));  
  16. for(FileStatus f:status){  
  17.     //打印全路徑,  
  18.     System.out.println(f.getPath().toString());  
  19.     //打印最後一級目錄名  
  20.     //System.out.println(f.getPath().getName());  
  21. }  






最後一個複雜,直接使用正則,會比較繁瑣,並且假若有一些其餘的邏輯在裏面會比較難控制,好比說你拿到這個日期,會從redis裏面再次匹配,是否存在,而後在作某些決定。 

hadoop在globStatus的方法裏,提供了一個路徑重載,根據PathFilter類,經過正則再次過濾出咱們須要的文件便可,使用此類,咱們能夠以更靈活的方式,操做,過濾路徑,好比說上面的那個日期範圍的判斷,咱們就能夠根據全路徑中,截取出日期,再作一些判斷,而且能夠再次過濾低級的路徑,好比是pv,uv或keyword的路徑。 

實例代碼以下: 

調用代碼: 


 api

Java代碼   收藏代碼ide

  1. FileStatus[] status = fs.globStatus(new Path(basepath),new RegexExcludePathAndTimeFilter(rexp_date,rexp_business, "2015-04-04",  "2015-04-06"));  



處理代碼: 工具

Java代碼   收藏代碼oop

  1. /** 
  2.      * 實現PathFilter接口使用正則過濾 
  3.      * 所需數據 
  4.      * 增強版,按時間範圍,路徑過濾 
  5.      * @author qindongliang 
  6.      * 大數據交流羣:(1號羣) 376932160 (2號羣) 415886155 
  7.      *  
  8.      * **/  
  9.     static class RegexExcludePathAndTimeFilter implements PathFilter{  
  10.          //日期的正則  
  11.          private final  String regex;  
  12.          //時間開始過濾  
  13.          private final  String start;  
  14.          //時間結束過濾  
  15.          private final  String end;  
  16.          //業務過濾  
  17.          private final  String regex_business;  
  18.        
  19.         public RegexExcludePathAndTimeFilter(String regex,String regex_business,String start,String end) {  
  20.             this.regex=regex;  
  21.             this.start=start;  
  22.             this.end=end;  
  23.             this.regex_business=regex_business;  
  24.         }  
  25.           
  26.         @Override  
  27.         public boolean accept(Path path) {  
  28.             String data[]=path.toString().split("/");  
  29.             String date=data[7];  
  30.             String business=data[9];  
  31.             return  Pattern.matches(regex_business, business)&&Pattern.matches(regex,date) && TimeTools.checkDate(start, end, date);  
  32.         }  
  33.           
  34.           
  35.           
  36.     }  
  37.       
  38.     /**日期比較的工具類**/  
  39.     static class TimeTools{  
  40.           
  41.         final static String DATE_FORMAT="yyyy-MM-dd";  
  42.           
  43.         final static SimpleDateFormat sdf=new SimpleDateFormat(DATE_FORMAT);  
  44.           
  45.         public static boolean cnull(String checkString){  
  46.             if(checkString==null||checkString.equals("")){  
  47.                 return false;  
  48.             }  
  49.             return true;  
  50.         }  
  51.           
  52.         /** 
  53.          * @param start 開始時間 
  54.          * @param end 結束時間 
  55.          * @param path 比較的日期路徑 
  56.          * **/  
  57.         public static boolean checkDate(String start,String end,String path){  
  58.             long startlong=0;  
  59.             long endlong=0;  
  60.             long pathlong=0;  
  61.             try{  
  62.              if(cnull(start)){  
  63.                  startlong=sdf.parse(start).getTime();  
  64.              }  
  65.              if(cnull(end)){  
  66.                  endlong=sdf.parse(end).getTime();  
  67.              }  
  68.              if(cnull(path)){  
  69.                  pathlong=sdf.parse(path).getTime();  
  70.              }  
  71.             //當end日期爲空時,只取start+的日期  
  72.             if(end==null||end.equals("")){  
  73.                 if(pathlong>=startlong){  
  74.                     return true;  
  75.                 }else{  
  76.                     return false;  
  77.                 }  
  78.             }else{//當end不爲空時,取日期範圍直接比較  
  79.                 //過濾在規定的日期範圍以內  
  80.                 if(pathlong>=startlong&&pathlong<=endlong){  
  81.                     return true;  
  82.                 }else{  
  83.                     return false;  
  84.                 }  
  85.                   
  86.             }  
  87.               
  88.             }catch(Exception e){  
  89.                 log.error("路徑日期轉換異常: 開始日期:  "+start+"  結束日期 "+end+"  比較日期: "+path+"  異常: "+e);  
  90.             }  
  91.               
  92.             return false;  
  93.         }  





總結: 

(1)若是隻是簡單的路徑過濾,那麼直接在路徑中就使用正則通配是最簡單強大的。 

(2)若是是比較複雜的路徑過濾,建議自定義PathFilter來封裝過濾代碼。 

(3)若是是在建設初期的就把各個文件夾目錄文件的存儲規劃好,這樣是最好不過了,好比上面的pv是一個文件夾,而後下面是各個日期,uv是一個文件夾,而後下面是各類日期,這樣從業務的角度就按維度切分好,那麼咱們處理起來也是很是方便的,這也就是Hive裏面對應的分區功能,有了分區,咱們就能夠按需所取,儘可能避免沒必要要的一些額外操做。 
大數據

相關文章
相關標籤/搜索