1.背景
需求是使用sqoop导出HDFS上的数据到MySQL,理论上来说是个很简单的需求,写了个如下的sqoop脚本:
sqoop export \
--connect jdbc:mysql://host:port/db \
--username username \
--password passwd \
--table tableName \
--export-dir hdfs://path/20180919/10/44 \
-m 1 \
--verbose \
--input-fields-terminated-by '\001'
执行的时候报错:
java.io.IOException: Can't export data, please check failed map task logs
at org.apache.sqoop.mapreduce.TextExportMapper.map(TextExportMapper.java:122)
2.错误分析
因为sqoop最终会生成mr作业,所以在yarn监控页面根据application_id找到作业,查看日志如上面所示,意思是类型转换错误。因此想到HDFS上文件中的time字段是String类型,而MySQL中是timestamp类型,可能无法转换导致的。因此加上了参数--map-column-java time=String。
整个sqoop脚本变为如下所示:
sqoop export \
--connect jdbc:mysql://host:port/db \
--username username \
--password passwd \
--table tableName \
--export-dir hdfs://path/20180919/10/44 \
-m 1 \
--verbose \
--input-fields-terminated-by '\001' \
--map-column-java time=String
再次尝试发现还是报错。
然后分析sqoop生成的Java类,最终发现是因为字段错位导致的。hdfs的数据有20个字段,同样MySQL里面的业务字段有20个,但是在这20个字段之前多了一个自增的id,导致整个字段对应出现问题。
3.解决方案
使用--columns参数指定字段。如下所示:
sqoop export \
--connect jdbc:mysql://host:port/db \
--username username \
--password passwd \
--table tableName \
--export-dir hdfs://path/20180919/10/44 \
-m 1 \
--verbose \
--input-fields-terminated-by '\001' \
--map-column-java time=String \
--columns="col1,col2,col3"
再次测试,正常运行。