You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用warehouse-dir的Sqoop任务重试时输出目录已存在错误的解决方法

解决Sqoop使用warehouse-dir时MapReduce重试的目录已存在问题

我在Sqoop任务中因特定需求使用warehouse-dir参数而非target-dir,但当MapReduce任务重试时,会抛出如下错误。由于只是重试操作,执行任务前删除相关目录并无影响,请问该如何解决此问题?

日志信息:

Fetching child yarn jobs tag id : oozie-8b2856ac4965b4431c0e9a9b80fb2bda 
2018-05-23 22:45:15,153 [main] INFO org.apache.hadoop.yarn.client.RMProxy - Connecting to ResourceManager at ip.compute.internal/172.31.4.192:8032 
Child yarn jobs are found - application_1527093425690_0231 
Found [1] Map-Reduce jobs from this launcher 
Killing existing jobs and starting over: error message: output directory already exists: 
2018-05-23 22:45:26,374 [main] ERROR org.apache.sqoop.tool.ImportTool - Import failed: org.apache.hadoop.mapred.FileAlreadyExistsException: Output directory /path_to_directory_in_hdfs/already exists 
at org.apache.hadoop.mapreduce.lib.output.FileOutputFormat.checkOutputSpecs(FileOutputFormat.java:146) 
at org.apache.hadoop.mapreduce.JobSubmitter.checkSpecs(JobSubmitter.java:270) 
at org.apache.hadoop.mapreduce.JobSubmitter.submitJobInternal(JobSubmitter.java:143) 
at org.apache.hadoop.mapreduce.Job$10.run(Job.java:1307) 
at org.apache.hadoop.mapreduce.Job$10.run(Job.java:1304) 
at java.security.AccessController.doPrivileged(Native Method) 
at javax.security.auth.Subject.doAs(Subject.java:415) 
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1920) 
at org.apache.hadoop.mapreduce.Job.submit(Job.java:1304) 
at org.apache.hadoop.mapreduce.Job.waitForCompletion(Job.java:1325) 
at org.apache.sqoop.mapreduce.ImportJobBase.doSubmitJob(ImportJobBase.java:203) 
at org.apache.sqoop.mapreduce.ImportJobBase.runJob(ImportJobBase.java:176) 
at org.apache.sqoop.mapreduce.ImportJobBase.runImport(ImportJobBase.java:273) 
at org.apache.sqoop.manager.SqlManager.importTable(SqlManager.java:692) 
at org.apache.sqoop.tool.ImportTool.importTable(ImportTool.java:513) 
at org.apache.sqoop.tool.ImportTool.run(ImportTool.java:621) 
at org.apache.sqoop.tool.JobTool.execJob(JobTool.java:243) 
at org.apache.sqoop.tool.JobTool.run(JobTool.java:298) 
at org.apache.sqoop.Sqoop.run(Sqoop.java:147) 
at org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:70) 
at org.apache.sqoop.Sqoop.runSqoop(Sqoop.java:183) 
at org.apache.sqoop.Sqoop.runTool(Sqoop.java:234) 
at org.apache.sqoop.Sqoop.runTool(Sqoop.java:243) 
at org.apache.sqoop.Sqoop.main(Sqoop.java:252) 
at org.apache.oozie.action.hadoop.SqoopMain.runSqoopJob(SqoopMain.java:196) 
at org.apache.oozie.action.hadoop.SqoopMain.run(SqoopMain.java:179) 
at org.apache.oozie.action.hadoop.LauncherMain.run(LauncherMain.java:60) 
at org.apache.oozie.action.hadoop.SqoopMain.main(SqoopMain.java:48) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
at java.lang.reflect.Method.invoke(Method.java:606) 
at org.apache.oozie.action.hadoop.LauncherMapper.map(LauncherMapper.java:234) 
at org.apache.hadoop.mapred.MapRunner.run(MapRunner.java:54) 
at org.apache.hadoop.mapred.MapTask.runOldMapper(MapTask.java:453) 
at org.apache.hadoop.mapred.MapTask.run(MapTask.java:343) 
at org.apache.hadoop.mapred.YarnChild$2.run(YarnChild.java:164) 
at java.security.AccessController.doPrivileged(Native Method) 
at javax.security.auth.Subject.doAs(Subject.java:415) 
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1920) 
at org.apache.hadoop.mapred.YarnChild.main(YarnChild.java:158) 
<<< Invocation of Sqoop command completed <<< 

针对这个问题,核心原因是使用warehouse-dir时,Sqoop会在指定路径下自动生成对应表的子目录作为MapReduce的输出路径,而MapReduce任务重试时会严格检查输出目录是否存在,一旦存在就抛出FileAlreadyExistsException。既然你确认重试前删除目录无业务影响,这里提供几个高效的解决办法:

方法1:给Sqoop命令添加覆盖输出的参数

这是最直接的方案,不需要额外的工作流调整,只需在你的Sqoop命令末尾添加MapReduce的覆盖配置参数:

-Dmapreduce.output.fileoutputformat.overwrite=true

这个参数会强制MapReduce跳过目录存在性检查,直接覆盖已有目录的内容,完美适配重试场景,操作成本最低。

方法2:在Oozie工作流中前置目录清理步骤

如果不想修改Sqoop命令的参数,可以在Oozie的workflow.xml里,给Sqoop任务添加一个前置的Shell Action,专门负责删除目标目录:

<action name="clean-sqoop-output-dir">
    <shell xmlns="uri:oozie:shell-action:0.1">
        <job-tracker>${jobTracker}</job-tracker>
        <name-node>${nameNode}</name-node>
        <exec>hdfs</exec>
        <argument>dfs</argument>
        <argument>-rm</argument>
        <argument>-r</argument>
        <argument>-f</argument>
        <argument>/path_to_directory_in_hdfs/</argument>
        <capture-output/>
    </shell>
    <ok to="sqoop-import-task"/>
    <error to="fail"/>
</action>

<action name="sqoop-import-task">
    <!-- 这里是你原有的Sqoop Action配置 -->
</action>

添加这个步骤后,每次执行Sqoop任务前都会先强制删除目标目录,从根源上避免了目录已存在的问题。

方法3:精准清理warehouse-dir下的表目录

如果你的导入表名固定,还可以通过脚本拼接出warehouse-dir下的具体表目录路径(比如/your_warehouse_dir/your_table_name),然后执行删除操作。这种方式更精准,不会误删同一warehouse下的其他表数据。

注意事项

需要提醒的是,旧版本的Sqoop中,--delete-target-dir参数仅对target-dir生效,无法清理warehouse-dir自动生成的表目录,所以不要依赖这个参数解决当前问题。

内容的提问来源于stack exchange,提问作者systemdebt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:02:47