问题场景
之前在《Dolphinscheduler调度Datax任务读取Hive分区表案例》博客中我分享了调度任务读取hive分区的几个场景,当时提到了分区中有空文件的解决方案。
除此之外,我们还遇到了空分区的场景,即该分区没有数据,连所谓的空文件也没有,这种场景会报以下异常。
未能找到待读取的文件,请确认您的配置项path……
问题定位
这种问题一般产生的原因是当日抽取源表往hive写数据时,创建了当日的分区,但是抽取的源表却没有当天的数据。
通过报错信息我们定位到datax源码的位置为
com.alibaba.datax.plugin.reader.hdfsreader.HdfsReader
public List<Configuration> split(int adviceNumber) {
LOG.info("split() begin...");
List<Configuration> readerSplitConfigs = new ArrayList<Configuration>();
// warn:每个slice拖且仅拖一个文件,
// int splitNumber = adviceNumber;
int splitNumber = this.sourceFiles.size();
if (0 == splitNumber) {
throw DataXException.asDataXException(HdfsReaderErrorCode.EMPTY_DIR_EXCEPTION,
String.format("未能找到待读取的文件,请确认您的配置项path: %s", this.readerOriginConfig.getString(Key.PATH)));
}
List<List<String>> splitedSourceFiles = this.splitSourceFiles(new ArrayList<String>(this.sourceFiles), splitNumber);
for (List<String> files : splitedSourceFiles) {
Configuration splitedConfig = this.readerOriginConfig.clone();
splitedConfig.set(Constant.SOURCE_FILES, files);
readerSplitConfigs.add(splitedConfig);
}
这里源文件的目录文件数为空时会直接抛异常并任务报错终止,而我们的期望是,可以在日志中有提示,但是任务不能报错终止。
问题解决
所以最简单的办法就是把throw的异常,仅用LOG.warn打印出来即可。
代码修改为:
public List<Configuration> split(int adviceNumber) {
LOG.info("split() begin...");
List<Configuration> readerSplitConfigs = new ArrayList<Configuration>();
// warn:每个slice拖且仅拖一个文件,
// int splitNumber = adviceNumber;
int splitNumber = this.sourceFiles.size();
if (0 == splitNumber) {
// throw DataXException.asDataXException(HdfsReaderErrorCode.EMPTY_DIR_EXCEPTION,
// String.format("未能找到待读取的文件,请确认您的配置项path: %s", this.readerOriginConfig.getString(Key.PATH)));
//异常处理逻辑修改
LOG.warn(String.format("未能找到待读取的文件,请确认您的配置项path: %s", this.readerOriginConfig.getString(Key.PATH)));
LOG.info("split() end");
LOG.info("Task exited with return code 0");
System.exit(0);
}
重新打包后,替换安装目录下hdfsreader下的hdfsreader-0.0.1-SNAPSHOT.jar包。(记得如果是ha,还要提前将hdfs-site和core-site文件打到包里,可参考《Dolphinscheduler调度Datax任务读取Hive分区表案例》)。