sqoop导入自由格式查询错误

时间:2013-09-28 00:24:43

标签: forms import sqoop

我注意到sqoop import的一个奇怪问题。我试图导入的数据在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)。

之前有没有人见过这种行为?关于如何解决这个问题的任何想法?

2 个答案:

答案 0 :(得分:5)

我尝试使用不同的MySQL驱动程序版本执行相同的命令 - 虽然在所有情况下都发生了相同的错误,但这次的消息更加清晰:

13/10/21 22:19:18 INFO mapred.JobClient: Task Id : attempt_201309130032_0308_m_000000_0,   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: Cannot convert value '0000-00-00 00:00:00' from column 7 to TIMESTAMP.
    at com.mysql.jdbc.ResultSet.getTimestampFromBytes(ResultSet.java:6886)
    at com.mysql.jdbc.ResultSet.getTimestampInternal(ResultSet.java:6921)
    at com.mysql.jdbc.ResultSet.getTimestamp(ResultSet.java:6245)
    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

所以基本的问题是'0000-00-00 00:00:00'日期的值存储在我们的数据库中,但驱动程序无法处理(我已经尝试了几个版本,但没有一个工作)。在sqoop中使用带有自由格式查询选项的原始sql时,驱动程序会尝试将此日期转换为失败的日期对象,从而导致上述错误。请注意,如果使用视图提取相同的日期值,则不会发生这种情况 - 在这种情况下,驱动程序似乎不会尝试将此值转换为日期对象。无论出于何种原因,MySQL驱动程序和服务器似乎都不同步,无法处理无效日期。

来自MySQL docs

As of 5.0.2, the server requires that month and day values be legal, and not merely in   the range 1 to 12 and 1 to 31, respectively. With strict mode disabled, invalid dates such   as '2004-04-31' are converted to '0000-00-00' and a warning is generated. With strict mode   enabled, invalid dates generate an error.

我们的旧版数据库服务器已禁用严格模式,每当旧应用程序尝试插入无效日期(例如“2004-04-31”)时,它都会转换为“0000-00-00”,而这不是由驱动程序处理如上所述的原始sql案例。一旦使用where子句中的过滤器删除这些记录,sqoop导入就会按预期工作。

答案 1 :(得分:0)

您可以在sqoop命令中使用此JDBC URL

JDBC:MySQL的:// yourserver:3306 / yourdatabase zeroDateTimeBehavior = convertToNull

这项工作对我来说

相关问题