起因是应用层的数据出现误差,比正确的数据少了1条,在检查了代码之后发现并无问题,而且考虑到如果真的是代码问题,那么为什么独独差了这么1条。所以我就怀疑是模型层或者贴源层的数据存在问题,于是先检查模型层,果然出现了几条数据错位,顺着往上找,问题根源在于贴源层。
所以我猜想肯定是调度的时候出现了什么故事。
贴下我发生问题的sqoop参数:
#!/bin/sh
/home/master/software/sqoop/bin/sqoop import \
--connect jdbc:mysql://地址/数据库名 \
--username 用户名 \
--password 密码 \
--table 表名 \
--fields-terminated-by "\t" \
--hive-delims-replacement "@" \
--lines-terminated-by "\n" \
--hive-import \
--hive-overwrite \
--delete-target-dir \
--hive-database 数据库 \
--hive-table 表名 \
-m 1 \
这个脚本说起来是种非常偷懒的调度方式,一不用自己建表,二不用指定hdfs目录,源库的表是什么样子,导入到hadoop后就是什么样子。缺点也很明显,太呆板,不能自由选择字段,也不能对字段进行微处理,而且调度过来的字段数据类型也会发生改变。
一开始我以为是分隔符不合适,毕竟从一开始就在分隔符这里吃过大亏,于是前后更换了十来个分隔符,包括(\u0000,\u0001,\u0002,\u0003,\u0004,\u0005,\u0006,\u0007等,具体还有啥请参考大神的文章:Hive分隔符_飞朋的博客-CSDN博客_hive分隔符)试了个遍,重新调度,结果总是这几条数据的某个字段往后错了一位。因此基本上靠更换分隔符的方式没有什么希望了。
我研究了一下异常数据的特征,发现可能是某个字段被一拆为二了,导致后续字段统统错位,所以尝试着换一种方式调度,即加入参数columns,这个参数可以让我们自由选择字段,在去掉了最开始发生错位的那个字段之后重新调度,跟我想的没错,剩下的字段结果正常了,贴下加了参数的脚本:
#!/bin/sh
/home/master/software/sqoop/bin/sqoop import \
--connect jdbc:mysql://地址/数据库名 \
--username 用户名 \
--password 密码 \
--table 表名 \
--columns 字段1,字段2,字段3 \
--fields-terminated-by "\t" \
--hive-delims-replacement "@" \
--lines-terminated-by "\n" \
--hive-import \
--hive-overwrite \
--delete-target-dir \
--hive-database 数据库 \
--hive-table 表名 \
-m 1 \
然而虽然剩下的字段结果正常,总不能丢下那个出问题的不管,所以我又尝试了另外一种调度方式,query的参与,这个相对于columns参数来说,更麻烦,需要指定target-dir的目录,但更自由,可以用hive语句来对数据进行细微的处理。
#!/bin/sh
/home/master/software/sqoop/bin/sqoop import \
--connect jdbc:mysql://地址/数据库名 \
--username 用户名 \
--password 密码 \
--query "select 字段1,字段2,字段3 where \$CONDITIONS" \
--delete-target-dir \
--fields-terminated-by "\t" \
--hive-delims-replacement "\001" \
--lines-terminated-by "\n" \
--hive-import \
--hive-overwrite \
--target-dir /user/hive/warehouse/pdd.db/video \
--hive-database 数据库 \
--hive-table 表名 \
-m 1 \
在研究了发生问题数据之后,发现这几条数据的共同特征是字段的值前面有空格,所以首先用了trim函数去掉了这个字段的空格,结果很意外,没有用。
正发愁,突然看到了键盘上的TAB键。没错,伪装成空格的TAB键,用了replace函数把TAB去掉,终于解决了这个困扰大半天的问题。
另外解决问题时有几个小插曲,有的是因为马虎,有的是因为懂得少,也分享一下吧。
首先是报错Unknown column '' in 'field list',这个明面上意思是在源库找不到对应的字段,我检查之后发现在更换query的时候忘记删掉columns这个单词了,它作为字段在源库中当然找不到。
然后是报错ERROR tool.ImportTool: Encountered IOException running import job: java.io.IOException: Query [select 字段1,字段2,字段3from pdd_video] must contain '$CONDITIONS' in WHERE clause.这个错包含信息也很明显,query后面没有加where \$CONDITIONS,我不懂为什么要加这个,但不加就报错。
最后是At minimum, you must specify --connect and –table Arguments to mysqldump and other subprograms may be supplied after a '--' on the command line. ./sqoop_import_video1.sh:行4: --username: 未找到命令。基本上这种问题都是参数后面没有加‘\’这个符号,或者加了符号但符号前面没有加小空格,一定要注意加空格啊。
这个问题总结起来思路如下:发现问题-检查代码-检查上层数据-检查上游数据-检查调度命令-检查异常数据具体的值的特征-找到问题根本-寻找解决方案-解决问题并复盘。
最后仍有个疑问,是不是在调度的过程中,字段的分割全部都是默认用TAB处理的,所以字段的值中存在TAB这个大空格之后,就出现了字段一分为二的情况?希望有大佬能给解答。