问题
最近在一个大数据的项目开发中使用到了数据同步工具DataX,但在使用过程中发现了DataX对HIve分区表的支持不太友好。
具体体现在将数据库中的数据同步到HIVE分区表时,写入目录为HIVE表分区为dt=XXXX,如果不提前创建该分区,会报目录不存在的错误,如下图:
原因分析
这个错误是由于DataX不支持在HDFS上创建目录导致的。
解决办法
二次开发DataX,在写入时检测目录,若目录不存在自动创建此分区目录。
步骤:1.从GitHub下载datax源码 链接
2.修改hdfswriter目录下的HdfsWriter.java源码,重写里面的prepare方法:
@Override
public void prepare() {
//若路径已经存在,检查path是否是目录
if (hdfsHelper.isPathexists(path)) {
if (!hdfsHelper.isPathDir(path)) {
throw DataXException.asDataXException(HdfsWriterErrorCode.ILLEGAL_VALUE,
String.format("您配置的path: [%s] 不是一个合法的目录, 请您注意文件重名, 不合法目录名等情况.",
path));
}
//根据writeMode对目录下文件进行处理
Path[] existFilePaths = hdfsHelper.hdfsDirList(path, fileName);
boolean isExistFile = false;
if (existFilePaths.length > 0) {
isExistFile = true;
}
if ("append".equalsIgnoreCase(writeMode)) {
LOG.info(String.format("由于您配置了writeMode append, 写入前不做清理工作, [%s] 目录下写入相应文件名前缀 [%s] 的文件",
path, fileName));
} else if ("nonconflict".equalsIgnoreCase(writeMode) && isExistFile) {
LOG.info(String.format("由于您配置了writeMode nonConflict, 开始检查 [%s] 下面的内容", path));
List<String> allFiles = new ArrayList<String>();
for (Path eachFile : existFilePaths) {
allFiles.add(eachFile.toString());
}
LOG.error(String.format("冲突文件列表为: [%s]", StringUtils.join(allFiles, ",")));
throw DataXException.asDataXException(HdfsWriterErrorCode.ILLEGAL_VALUE,
String.format("由于您配置了writeMode nonConflict,但您配置的path: [%s] 目录不为空, 下面存在其他文件或文件夹.", path));
} else if ("truncate".equalsIgnoreCase(writeMode) && isExistFile) {
LOG.info(String.format("由于您配置了writeMode truncate, [%s] 下面的内容将被覆盖重写", path));
hdfsHelper.deleteFiles(existFilePaths);
}
} else {
LOG.info(String.format("您配置的路径: [%s] 不存在,自动为您创建此路径", path));
hdfsHelper.createPath(path);
}
}
3.修改hdfswriter目录下的HdfsHelper.java源码,在里面添加createPath方法:
public boolean createPath(String filePath) {
Path path = new Path(filePath);
boolean exist = false;
try {
if (fileSystem.exists(path)) {
String message = String.format("文件路径[%s]已存在,无需创建!",
"message:filePath =" + filePath);
LOG.info(message);
exist = true;
} else {
exist = fileSystem.mkdirs(path);
}
} catch (IOException e) {
String message = String.format("创建文件路径[%s]时发生网络IO异常,请检查您的网络是否正常!",
"message:filePath =" + filePath);
LOG.error(message);
throw DataXException.asDataXException(HdfsWriterErrorCode.CONNECT_HDFS_IO_ERROR, e);
}
return exist;
}
4.打包修改后的源码,并替换掉集群的datax安装目录datax/plugin/writer/hdfswriter/hdfswriter-0.0.1-SNAPSHOT.jar即可。(在DataX-master根目录下的pom.xml文件核心组件、公共组件、reader/writer插件都以module的方式组装到一起了,把不需要的注释掉可加快打包速度)
处理结果
二次开发后完美运行: