我注意到 sqoop 导入有一个奇怪的问题。我尝试导入的数据在 MySQL DB 中采用以下形式:
<a1, a2, a3, d1, a4, a5, a6, a7, a8>
其中 a1, a2,..., a8 是 varchar 类型,d1 是时间戳类型。由于数据的规范化,我必须执行 JOIN 多个表才能获取这些列 - 如下所示:
SELECT t1.a1, t2.a2....... from table t1 INNER JOIN table t2 ON t1.t2_id = t2.id ........... WHERE <some condition>
最初,我从这样的视图开始:
CREATE OR REPLACE VIEW my_view AS
SELECT t1.a1, t2.a2....... from table t1 INNER JOIN table t2 ON t1.t2_id = t2.id ........... WHERE <some condition>
使用该视图导入 sqoop 命令如下:
sqoop import --connect [jdbc url] --username [user] --password [password] --table my_view --target-dir my_dir --split-by a5 --mysql-delimiters --verbose --boundary-query 'SELECT min(a5), max(a5) from t5'
这工作正常。由于 MySQL 视图没有像人们希望的那样优化,我想使用原始 SQL 来查看它是否会提高性能。为了测试这一点,我使用了自由格式查询:
sqoop import --connect [jdbc url] --username [user] --password [password] --query "SELECT t1.a1, t2.a2....... from table t1 INNER JOIN table t2 ON t1.t2_id = t2.id ............ WHERE <some condition> AND \$CONDITIONS" --target-dir my_dir --split-by a5 --mysql-delimiters --verbose --boundary-query 'SELECT min(a5), max(a5) from t5'
因此,在这种情况下,--query 参数有效地具有视图定义 SELECT 语句以及 sqoop 所需的 $CONDITIONS。但是,这不起作用。sqoop 导入了一半的记录并失败并出现以下奇怪的错误:
13/09/27 20:28:10 INFO mapred.JobClient: Task Id : attempt_201309130032_0122_m_000000_2, Status : FAILED
java.io.IOException: SQLException in nextKeyValue
at org.apache.sqoop.mapreduce.db.DBRecordReader.nextKeyValue(DBRecordReader.java:265)
at org.apache.hadoop.mapred.MapTask$NewTrackingRecordReader.nextKeyValue(MapTask.java:531)
at org.apache.hadoop.mapreduce.MapContext.nextKeyValue(MapContext.java:67)
at org.apache.hadoop.mapreduce.Mapper.run(Mapper.java:144)
at org.apache.sqoop.mapreduce.AutoProgressMapper.run(AutoProgressMapper.java:64)
at org.apache.hadoop.mapred.MapTask.runNewMapper(MapTask.java:764)
at org.apache.hadoop.mapred.MapTask.run(MapTask.java:364)
at org.apache.hadoop.mapred.Child$4.run(Child.java:255)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:396)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1190)
at org.apache.hadoop.mapred.Child.main(Child.java:249)
Caused by: java.sql.SQLException: Value 'xxxxxx' can not be represented as java.sql.Timestamp
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1078)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:989)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:975)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:920)
at com.mysql.jdbc.ResultSetRow.getTimestampFast(ResultSetRow.java:1102)
at com.mysql.jdbc.BufferRow.getTimestampFast(BufferRow.java:576)
at com.mysql.jdbc.ResultSetImpl.getTimestampInternal(ResultSetImpl.java:6592)
at com.mysql.jdbc.ResultSetImpl.getTimestamp(ResultSetImpl.java:6192)
at org.apache.sqoop.lib.JdbcWritableBridge.readTimestamp(JdbcWritableBridge.java:111)
at com.cloudera.sqoop.lib.JdbcWritableBridge.readTimestamp(JdbcWritableBridge.java:83)
at QueryResult.readFields(QueryResult.java:156)
at org.apache.sqoop.mapreduce.db.DBRecordReader.nextKeyValue(DBRecordReader.java:245)
... 11 more
据我所知,sqoop 正在尝试将其他一些列 (a3) 值解释为时间戳,并且转换失败,因为它只是一个字符串而不是日期类型。我还应该提到我们的一些数据很糟糕——我们在一些不应该存在的字段中有换行符和制表符,但日期字段确实有有效值——我什至尝试在 MySQL 中使用 REPLACE 函数来摆脱这些但是这是没有用的。
鉴于数据是相同的,并且在任何一种情况下都使用相同的 SELECT 语句,我希望结果是相同的(即,SELECT 返回的相同数量的记录被导入到 HDFS)。
有没有人见过这种行为?关于如何解决这个问题的任何想法?