今天导数遇到一个问题,通过sqoop import从 postgresql导数据到hive中后,发现查询出来全部都是空的:
检查导入命令,没有错啊:
[root@dthost25 ~]#
sqoop import --connect jdbc:postgresql://192.168.xxx.xxx:5432/xxxxdb --username xxxx --password xxxxxxx --table rule --hive-import --hive-database lmj_test --hive-table ori_yyts_rule --hive-overwrite --delete-target-dir --hive-drop-import-delims --hive-drop-import-delims --null-string '' --null-non-string '' -m5
执行过程中也没有报错,顺利导入数据:
#运行日志(部分):
.......
File Input Format Counters
Bytes Read=0
File Output Format Counters
Bytes Written=869101
19/06/06 11:32:16 INFO mapreduce.ImportJobBase: Transferred 848.7314 KB in 24.4734 seconds (34.6797 KB/sec)
19/06/06 11:32:16 INFO mapreduce.ImportJobBase: Retrieved 1266 records.
19/06/06 11:32:16 INFO manager.SqlManager: Executing SQL statement: SELECT t.* FROM "rule" AS t LIMIT 1
19/06/06 11:32:16 WARN hive.TableDefWriter: Column create_date had to be cast to a less precise type in Hive
19/06/06 11:32:16 WARN hive.TableDefWriter: Column last_update_date had to be cast to a less precise type in Hive
19/06/06 11:32:16 INFO hive.HiveImport: Loading uploaded data into Hive
19/06/06 11:32:17 INFO hive.HiveImport: Hive import complete.
那为什么会导致导入的数据全为NULL呢?
原因是在于,建hive表是设定的分割符不恰当,跟从postgresql导入过来的数据的分隔符不一样,所以导致hive切分不了数据,于是查询为空,但是这个过程,是不属于导入失败的,所以导入命令没有报错。
因为sqoop import实际上是把数据存放到hdfs对应路径上了,而不是“直接导入表里”,查询时,hive会从hdfs的路径上提取数据,再根据hive表的结构和定义,来向我们展示出类似表格的形式。因此,导入过程是不会报错的,但是因为hive定义的分隔符和存在hdfs上数据的分隔符不一致,所以查询是全为NULL的。
那么,是怎么样的不一样呢?
我们先来查询一下原来hive表的建表语句,用show create table xxxx
即可:
hive> show create table ori_yyts_rule;
OK
createtab_stmt
CREATE TABLE `ori_yyts_rule`(
`id` int,
`version` int,
`create_date` string,
`create_man` string,
`description` string,
`ext1` string,
`ext2` string,
`ext3` string,
`ext4` string,
`kind_code` string,
`last_update_date` string,
`last_update_man` string,
`rule_code` string,
`rule_message1` string,
`rule_message2` string,
`rule_type` string,
`rule_val` string,
`is_accord` string,
`is_accord_message` string)
COMMENT 'rule_code explanation'
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\n'
STORED AS INPUTFORMAT
'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
'hdfs://dthost21:8020/user/hive/warehouse/lmj_test.db/ori_yyts_rule'
TBLPROPERTIES (
'COLUMN_STATS_ACCURATE'='true',
'numFiles'='5',
'numRows'='0',
'rawDataSize'='0',
'totalSize'='869101',
'transient_lastDdlTime'='1559791620')
Time taken: 0.214 seconds, Fetched: 37 row(s)
可以看到分隔符为:FIELDS TERMINATED BY '\t'
,而从postgresql或者mysql来的数据的分隔符则应该为:FIELDS TERMINATED BY '\u0001'
,那我们只要改回来就可以正常导入了。
这里有个小窍门,其实用sqoop import 从postgresql或者mysql导数据时,会在hive上自动建表,建表时的分隔符也会自动设为FIELDS TERMINATED BY '\u0001'
。
引申一下,这个问题还会经常出现在从txt、excel或者其他数据源导入hive表这种场景下,原因其实都是原来的数据的分隔方式和hive表定义的不一致,大家以后遇到相似问题可以有意识地思考一下这种可能性。