设为首页 收藏本站
查看: 1013|回复: 0

[经验分享] Hadoop进阶之输入路径如何正则通配?

[复制链接]

尚未签到

发表于 2016-12-12 08:25:50 | 显示全部楼层 |阅读模式

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

DSC0000.jpg

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

   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上的存储结构图:

DSC0001.jpg

这是一个按日期每天生成的一个文件夹,当然这里可以有很多分维度的法,比如按照年,月,日,小时,来划分,具体情况应跟业务结合考虑。
看下,直接的根目录的下一级目录:
DSC0002.jpg

ok,存储结构清楚了,那么现在提几个需求
(1)只过滤出pv目录下的数据
(2)只过滤出uv目录下的数据
(3)只过滤出keyword目录下的数据
(4)只过滤出pv和uv的数据或者叫以v结尾的数据
(5)过滤2015年的数据
(6)过滤出某个时间范围内的数据比如2015-04-10到2015-04-17时间范围下的pv的数据

其实前个需求很简单都是一种需求:
hadoop里的FileStatus类是支持路径通配的,对应的写法如下:

        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的路径。
实例代码如下:
调用代码:

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

处理代码:
/**
* 实现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里面对应的分区功能,有了分区,我们就可以按需所取,尽量避免不必要的一些额外操作。


最后欢迎大家扫码关注微信公众号:我是攻城师,我们一起学习,进步和交流!(woshigcs)
本公众号的内容是有关搜索和大数据技术和互联网等方面内容的分享,也是一个温馨的技术互动交流的小家园,有什么问题随时都可以留言,欢迎大家来访!

DSC0003.jpg

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-312945-1-1.html 上篇帖子: hadoop dfs.datanode.du.reserved 预留空间配置方法 下篇帖子: hadoop job提交完成的整个过程介绍 zz
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表