1.問題背景
使用Sqoop把oracle數據庫中的一張表,這里假定為student,當中的數據導入到hdfs中,然后再創建hive的external表,location到剛才保存到hdfs中數據的位置。最后發現對hive中表特定條件進行count時結果和oracle中結果不一致。
1.1 導入數據到hdfs中/user/hadoop/student路徑下
sqoop import --connect "jdbc:oracle:thin:@//localhost:1521/student" --password "***" --username "***" --query "select * from student where name='zhangsan' and class_id='003' and \$CONDITIONS" --target-dir "/user/hadoop/student" --verbose -m 1
這個時候hdfs上/user/hadoop/student下就保存了從oracle上導入的表數據。
表數據在hdfs上是如何存儲的呢?注意這一點,造成了最后產生結果不一致的錯誤。
我們來看一看在hdfs上數據是如何存儲的。我們運行hadoop fs -cat /user/hadoop/student/part-m-00000,可以看到原來字段與字段之間都用‘,’分隔開,這是sqoop默認的,這時候,如果一個字段值當中包含‘,’,再向hive中插入數據時分隔就會出錯。因為hive也是用‘,’分隔的。
2.分析問題
對hive中表select count(*) from student的結果和oracle中select count(*) from studeng的結果進行比較,發現條數是一樣的,說明沒有少load數據。那為什么對特定條件結果就會不一致,而且hive中條數比oracle中少。也就是同時運行select count(*) from student where class_id='003'
最后,發現hive用逗號分隔數據時,有幾條數據字段內值包含有逗號,所以字段與值對應起來就亂套了,所以得不到正確結果。
我們建議用‘\001'來進行sqoop 導入數據時的 分割。也就是--fields-terminated-by <char>參數。參考:http://sqoop.apache.org/docs/1.4.2/SqoopUserGuide.html#_large_objects
最后優化后的sqoop語句為:
sqoop import --connect "jdbc:oracle:thin:@//localhost:1521/student" --password "***" --username "***" --query "select * from student where name='zhangsan' and class_id='003' and \$CONDITIONS" --target-dir "/user/hadoop/student" --fields-terminated-by "\001" --verbose -m 1