在hadoop的編程中,若是你是手寫MapReduce來處理一些數據,那麼就避免不了輸入輸出參數路徑的設定,hadoop裏文件基類FileInputFormat提供了以下幾種api來制定:
如上圖,裏面有
(1)addInputPath(),每次添加一個輸入路徑Path
(2)addInputPaths, 將多個路徑以逗號分割的字符串,做爲入參,支持多個路徑
(3)setInputPath ,設置一個輸入路徑Path,會覆蓋原來的路徑
(4)setInputPath , 設置多個路徑,支持Hadoop文件系統重寫的Path對象,這在JAVA裏是接口。
代碼以下:
html
Java代碼
redis
- FileInputFormat.setInputDirRecursive(job, true);//設置能夠遞歸讀取目錄
- FileInputFormat.addInputPath(job, new Path("path1"));
- FileInputFormat.addInputPaths(job, "path1,path2,path3,path....");
- FileInputFormat.setInputPaths(job, new Path("path1"),new Path("path2"));
- 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代碼
編程
- FileSystem fs = FileSystem.get(conf);
- //
- //過濾pv或uv的目錄數據
- String basepath="/user/d1/DataFileShare/Search/*/*/{pv,uv}";
- //過濾v結尾的目錄數據
- String basepath="/user/d1/DataFileShare/Search//*/*/*v";
- //過濾uv的數據
- String basepath="/user/d1/DataFileShare/Search//*/*/uv";
- //過濾pv的數據
- String basepath="/user/d1/DataFileShare/Search//*/*/pv";
-
- //過濾2015年的pv的數據
- String basepath="/user/d1/DataFileShare/Search/2015*/*/pv";
- //獲取globStatus
- FileStatus[] status = fs.globStatus(new Path(basepath));
- for(FileStatus f:status){
- //打印全路徑,
- System.out.println(f.getPath().toString());
- //打印最後一級目錄名
- //System.out.println(f.getPath().getName());
- }
最後一個複雜,直接使用正則,會比較繁瑣,並且假若有一些其餘的邏輯在裏面會比較難控制,好比說你拿到這個日期,會從redis裏面再次匹配,是否存在,而後在作某些決定。
hadoop在globStatus的方法裏,提供了一個路徑重載,根據PathFilter類,經過正則再次過濾出咱們須要的文件便可,使用此類,咱們能夠以更靈活的方式,操做,過濾路徑,好比說上面的那個日期範圍的判斷,咱們就能夠根據全路徑中,截取出日期,再作一些判斷,而且能夠再次過濾低級的路徑,好比是pv,uv或keyword的路徑。
實例代碼以下:
調用代碼:
api
Java代碼
ide
- FileStatus[] status = fs.globStatus(new Path(basepath),new RegexExcludePathAndTimeFilter(rexp_date,rexp_business, "2015-04-04", "2015-04-06"));
處理代碼: 工具
Java代碼
oop
- /**
- * 實現PathFilter接口使用正則過濾
- * 所需數據
- * 增強版,按時間範圍,路徑過濾
- * @author qindongliang
- * 大數據交流羣:(1號羣) 376932160 (2號羣) 415886155
- *
- * **/
- static class RegexExcludePathAndTimeFilter implements PathFilter{
- //日期的正則
- private final String regex;
- //時間開始過濾
- private final String start;
- //時間結束過濾
- private final String end;
- //業務過濾
- private final String regex_business;
-
- public RegexExcludePathAndTimeFilter(String regex,String regex_business,String start,String end) {
- this.regex=regex;
- this.start=start;
- this.end=end;
- this.regex_business=regex_business;
- }
-
- @Override
- public boolean accept(Path path) {
- String data[]=path.toString().split("/");
- String date=data[7];
- String business=data[9];
- return Pattern.matches(regex_business, business)&&Pattern.matches(regex,date) && TimeTools.checkDate(start, end, date);
- }
-
-
-
- }
-
- /**日期比較的工具類**/
- static class TimeTools{
-
- final static String DATE_FORMAT="yyyy-MM-dd";
-
- final static SimpleDateFormat sdf=new SimpleDateFormat(DATE_FORMAT);
-
- public static boolean cnull(String checkString){
- if(checkString==null||checkString.equals("")){
- return false;
- }
- return true;
- }
-
- /**
- * @param start 開始時間
- * @param end 結束時間
- * @param path 比較的日期路徑
- * **/
- public static boolean checkDate(String start,String end,String path){
- long startlong=0;
- long endlong=0;
- long pathlong=0;
- try{
- if(cnull(start)){
- startlong=sdf.parse(start).getTime();
- }
- if(cnull(end)){
- endlong=sdf.parse(end).getTime();
- }
- if(cnull(path)){
- pathlong=sdf.parse(path).getTime();
- }
- //當end日期爲空時,只取start+的日期
- if(end==null||end.equals("")){
- if(pathlong>=startlong){
- return true;
- }else{
- return false;
- }
- }else{//當end不爲空時,取日期範圍直接比較
- //過濾在規定的日期範圍以內
- if(pathlong>=startlong&&pathlong<=endlong){
- return true;
- }else{
- return false;
- }
-
- }
-
- }catch(Exception e){
- log.error("路徑日期轉換異常: 開始日期: "+start+" 結束日期 "+end+" 比較日期: "+path+" 異常: "+e);
- }
-
- return false;
- }
總結:
(1)若是隻是簡單的路徑過濾,那麼直接在路徑中就使用正則通配是最簡單強大的。
(2)若是是比較複雜的路徑過濾,建議自定義PathFilter來封裝過濾代碼。
(3)若是是在建設初期的就把各個文件夾目錄文件的存儲規劃好,這樣是最好不過了,好比上面的pv是一個文件夾,而後下面是各個日期,uv是一個文件夾,而後下面是各類日期,這樣從業務的角度就按維度切分好,那麼咱們處理起來也是很是方便的,這也就是Hive裏面對應的分區功能,有了分區,咱們就能夠按需所取,儘可能避免沒必要要的一些額外操做。 大數據