hadoop输入路径正则通配

在hadoop的编程中,如果你是手写MapReduce来处理一些数据,那么就避免不了输入输出参数路径的设定,hadoop里文件基类FileInputFormat提供了如下几种api来制定:

(1)addInputPath(),每次添加一个输入路径Path
(2)addInputPaths, 将多个路径以逗号分割的字符串,作为入参,支持多个路径
(3)setInputPath ,设置一个输入路径Path,会覆盖原来的路径
(4)setInputPath , 设置多个路径,支持Hadoop文件系统重写的Path对象,这在JAVA里是接口。 

代码如下: 

<span style="font-size:14px;">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....");</span>

而真正用的时候,我们只需要根据业务使用上面的其中一个路径即可。
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类是支持路径通配的,对应的写法如下:

<span style="font-size:14px;">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());  
}  </span>

最后一个复杂,直接使用正则,会比较繁琐,而且假如有一些其他的逻辑在里面会比较难控制,比如说你拿到这个日期,会从redis里面再次匹配,是否存在,然后在做某些决定。 

hadoop在globStatus的方法里,提供了一个路径重载,根据PathFilter类,通过正则再次过滤出我们需要的文件即可,使用此类,我们可以以更灵活的方式,操作,过滤路径,比如说上面的那个日期范围的判断,我们就可以根据全路径中,截取出日期,再做一些判断,并且可以再次过滤低级的路径,比如是pv,uv或keyword的路径。 

实例代码如下: 


调用代码:

 

   <span style="font-size:14px;"> /**

    * 实现PathFilter接口使用正则过滤

    * 所需数据

    * 加强版,按时间范围,路径过滤

    * @author qindongliang

    *

    * **/

    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;

    } </span>

评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Xd聊架构

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值